首页 > 代码库 > 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 }
View Code

在重载操作中:

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为继承体系编写"=="运算符