虚函数与运算符重载(Virtual Operator Overloading)

a 夏天 提交于 2020-01-28 21:03:52

虚函数与运算符重载(Virtual Operator Overloading)

一、相关日志

运算符重载

http://blog.163.com/zhoumhan_0351/blog/static/399542272010027113311390

多态性与虚函数

http://blog.163.com/zhoumhan_0351/blog/static/3995422720100290234430

补充运算符重载

http://blog.163.com/zhoumhan_0351/blog/static/3995422720103182106992

二、虚函数与运算符重载

1、矩阵相乘的一个例子

//: C15:OperatorPolymorphism.cpp

// Polymorphism with overloaded operators

#include <iostream>

using namespace std;

class Matrix;

class Scalar;

class Vector;

class Math {

public:

  virtual Math& operator*(Math& rv) = 0;

  virtual Math& multiply(Matrix*) = 0;

  virtual Math& multiply(Scalar*) = 0;

  virtual Math& multiply(Vector*) = 0;

  virtual ~Math() {}

};

class Matrix : public Math {

public:

  Math& operator*(Math& rv) {

return rv.multiply(this); // 2nd dispatch

  }

  Math& multiply(Matrix*) {

cout << "Matrix * Matrix" << endl;

return *this;

  }

  Math& multiply(Scalar*) {

cout << "Scalar * Matrix" << endl;

return *this;

  }

  Math& multiply(Vector*) {

cout << "Vector * Matrix" << endl;

return *this;

  }

};

class Scalar : public Math  {

public:

  Math& operator*(Math& rv) {

return rv.multiply(this); // 2nd dispatch

  }

  Math& multiply(Matrix*) {

cout << "Matrix * Scalar" << endl;

return *this;

  }

  Math& multiply(Scalar*) {

cout << "Scalar * Scalar" << endl;

return *this;

  }

  Math& multiply(Vector*) {

cout << "Vector * Scalar" << endl;

return *this;

  }

};

class Vector : public Math  {

public:

  Math& operator*(Math& rv) {

return rv.multiply(this); // 2nd dispatch

  }

  Math& multiply(Matrix*) {

cout << "Matrix * Vector" << endl;

return *this;

  }

  Math& multiply(Scalar*) {

cout << "Scalar * Vector" << endl;

return *this;

  }

  Math& multiply(Vector*) {

cout << "Vector * Vector" << endl;

return *this;

  }

};

int main() {

  Matrix m; Vector v; Scalar s;

  Math* math[] = { &m, &v, &s };

  for(int i = 0; i < 3; i++)

for(int j = 0; j < 3; j++) {

  Math& m1 = *math[i];

  Math& m2 = *math[j];

  m1 * m2;

}

} ///:~

从中我们可以看到,我们使用了多重指派(multiple dispatching),一个单一虚函数调用引起了第二个虚函数的调用。

2、关于向下类型

当然我们应当尽量避免。如果实在避免不了。用显式转换函数。

C++的显式类型转换

http://blog.163.com/zhoumhan_0351/blog/static/39954227201031695850264

//: C15:DynamicCast.cpp

#include <iostream>

using namespace std;

class Pet { public: virtual ~Pet(){}};

class Dog : public Pet {};

class Cat : public Pet {};

int main() {

  Pet* b = new Cat; // Upcast

  // Try to cast it to Dog*:

  Dog* d1 = dynamic_cast<Dog*>(b);

  // Try to cast it to Cat*:

  Cat* d2 = dynamic_cast<Cat*>(b);

  cout << "d1 = " << (long)d1 << endl;

  cout << "d2 = " << (long)d2 << endl;

} ///:~

使用dynamic_cast时,必须对一个真正多态的层次进行操作(它含有虚函数),这是因为dynamic_cast使用了存储在VTABLE中的信息来判断实际的类型。由上可见,不正确的向下转换返回了0值。但是我们不能确保指针要完全一样,因为在向上类型转换和向下类型转换时指针会发生调整。(尤其是多重继承)

    static_cast有时比dynamic_cast高效。

   //: C15:StaticHierarchyNavigation.cpp

// Navigating class hierarchies with static_cast

#include <iostream>

#include <typeinfo>

using namespace std;

class Shape { 

public:

 //virtual ~Shape() {}; 

};

class Circle : public Shape {};

class Square : public Shape {};

class Other {};

int main() {

  Circle c;

  Shape* s = &c; // Upcast: normal and OK

  // More explicit but unnecessary:

  s = static_cast<Shape*>(&c);

  // (Since upcasting is such a safe and common

  // operation, the cast becomes cluttering)

  Circle* cp = 0;

  Square* sp = 0;

  // Static Navigation of class hierarchies

  // requires extra type information:

  if(typeid(s) == typeid(cp)) // C++ RTTI

    cp = static_cast<Circle*>(s);

  if(typeid(s) == typeid(sp))

    sp = static_cast<Square*>(s);

  if(cp != 0)

    cout << "It's a circle!" << endl;

  if(sp != 0)

    cout << "It's a square!" << endl;

  // Static navigation is ONLY an efficiency hack;

  // dynamic_cast is always safer. However:

  // Other* op = static_cast<Other*>(s);

  // Conveniently gives an error message, while

  Other* op2 = (Other*)s;

  // does not

} ///:~

    RTTI允许我们得到进行向上类型转换时丢失的类型信息。dynamic_cast就是RTTI其中的一种。但是 static_cast转换是有风险的,我们一般用dynamic_cast。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!