虚函数与运算符重载(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。
来源:CSDN
作者:hopegrace
链接:https://blog.csdn.net/hopegrace/article/details/104101667