首页 > 代码库 > C++——使用RTTI为继承体系编写"=="运算符
C++——使用RTTI为继承体系编写"=="运算符
有下面一个继承体系,我们需要为其添加"=="操作符,该怎么办呢 ??
class Animal{};class Cat : public Animal{};class Dog : public Animal{};
如果我们为每个类重载"=="运算符,那么我们还需要重载子类与基类之间的"=="运算符,这样代码实现起来是很恐怖的。
我们可以尝试,只为基类重载一个"=="运算符,然后在基类中实现一个虚函数equal,在子类中去实现它。
实现代码如下:
1 #include <iostream> 2 #include <typeinfo> 3 #include <string> 4 using namespace std; 5 6 class Animal 7 { 8 public: 9 virtual bool equal(const Animal &other) const = 0;10 };11 12 class Cat : public Animal13 {14 public:15 bool equal(const Animal &other) const16 {17 //Cat Animal18 if(const Cat *pc = dynamic_cast<const Cat*>(&other)) 19 {20 return name_ == pc->name_;21 }22 return false;23 }24 25 private:26 string name_;27 };28 29 class Dog : public Animal30 {31 public:32 bool equal(const Animal &other) const33 {34 //Dog Animal35 if(const Dog *pd = dynamic_cast<const Dog*>(&other))36 {37 return name_ == pd->name_;38 }39 return false;40 }41 private:42 string name_;43 };44 45 bool operator==(const Animal &a, const Animal &b)46 {47 return typeid(a) == typeid(b) && a.equal(b);48 }49 50 int main(int argc, char const *argv[])51 {52 53 Cat c;54 Dog d;55 56 Animal *pa = &c;57 cout << (*pa == c) << endl;58 pa = &d;59 cout << (*pa == d) << endl;60 return 0;61 }
在重载操作中:
bool operator==(const Animal &a, const Animal &b){ return typeid(a) == typeid(b) && a.equal(b);}
typeid是一种类型识别运算符,如果要识别的类型不是class或不含有virtual函数,那么在编译期间自动识别,typeid指出静态类型,如果class中含有virtual函数,那么typeid在运行期间识别类型。
对equal的调用,显然使用了动态识别,总是能根据对象的实际类型,调用对应的equal版本。
在equal函数中,dynamic_cast使得对象进行了"向下塑形",static_cast与dynamic_cast之间有一些不同:
static_cast发生在编译期间,如果转化不通过,那么编译错误,如果编译无问题,那么转化一定成功。static_cast仍具有一定风险,尤其是向下塑形时,将Base*转化为Derived*时,指针可以转化,但是指针未必指向Derived对象。
dynamic_cast发生在运行期间,用于将Base的指针或者引用转化为派生类的指针或者引用,如果成功,返回正常的指针或引用,如果失败,返回NULL(指针),或者抛出异常(bad_cast)。
在"=="的重载中,我们保证了equal两个参数的类型相同,那么我们为何还需要在equal中“向下塑形”呢?
equal有可能被单独使用,所以other的类型未必和自己相同。
如果不进行转换,other是无法访问name属性的,因为Animal中没有name。
typeid和dynamic_cast是实现RTTI的主要手段。
C++——使用RTTI为继承体系编写"=="运算符