继承与派生

多重继承

多态

虚函数

下面这个例子是虚函数的一个典型应用,它虚就虚在“推迟绑定”或者“动态绑定”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。包含虚函数的类的实例会被编译器自动添加一个隐藏的成员变量,用于存储<动态绑定函数地址表>的地址。
虚函数只能借助于指针或者引用来达到多态的效果。

  1. class Shape { public: virtual void Draw(){}; };
  2. class Circle : public Shape { public: void Draw() { Draw Circle; } };
  3. class Rect : public Shape { public: void Draw() { Draw Rect; } };
  4. int main()
  5. {
  6. vector<Shape*> v;
  7. v.push_back(new Circle);
  8. v.push_back(new Rect);
  9. for (auto &it : v)
  10. it.Draw();
  11. }

基类中声明成员函数为虚函数后,派生类中的同名同参数函数是否声明为virtual都不影响动态绑定,但一般习惯性地在派生类中将与基类中声明为虚函数的同名同参数函数也声明为virtual便于代码阅读者知晓这是一个虚函数。
那么和基类中声明为虚函数的成员函数同名不同参数的函数呢?
https://stackoverflow.com/questions/411103/function-with-same-name-but-different-signature-in-derived-class
如果我们在派生类中没有重写基类中声明的虚函数,但是却有和基类中虚函数同名不同形参的成员函数,会隐藏基类中的所有同名虚函数。调用函数时的动态绑定,譬如调用下面代码中的q2->f(),由于q2是B类的指针,首先寻找B中有没有f这个函数,如果没找到则向上查询A类的虚函数表;只要找到了f函数,不论其形参如何都会停止向上层寻找,但此时B类中没有f(),只有f(int),因此会报“没有与参数列表匹配的重载函数”错误。
对虚函数进行重载是非常不建议的一种行为!

  1. class A
  2. {
  3. public:
  4. virtual void f() { cout << 1 << endl; }
  5. };
  6. class B : public A
  7. {
  8. public:
  9. void f(int) { cout << 2 << endl; }
  10. };
  11. class C : public B
  12. {
  13. public:
  14. void f(int) { cout << 3 << endl; }
  15. };
  16. int main()
  17. {
  18. A *p1 = new A, *p2 = new B, *p3 = new C;
  19. B *q2 = new B, *q3 = new C;
  20. p1->f(); // 结果为1
  21. p2->f(); // 结果为1,B中没有重写f(),调用A::f()
  22. p3->f(); // 结果为3,C中重写了f(),调用C::f()
  23. q2->f(); // 编译不通过,电脑会原地爆炸
  24. q2->f(1); // 结果为2
  25. q3->f(1); // 结果为2,f(int)没有动态绑定,q3是B*类型,C::f(int)不可见,调用B::f(int)
  26. }