继承和多态
继承
单继承
class A: [继承方式] B { };
多继承
class A: [继承方式] B, [继承方式] C { };
[继承方式]
即 public
,private
,protected
.
多继承的二义性
如图所示
类C同时继承B1,B2,在调用基类A的成员变量a时,编译器报错,不知道是从类B1还是从类B2继承来访问a。
解决方案是添加virtual,实质上编译器给变量成员添加了属性
class B1:virtual public A {};
class B2:virtual public A {};
由于产生歧义,工程上不建议使用。
多态
通过一个基类指针调用相同的函数,由于基类指针指向对象类类型不同,就会得到不同的效果和特征,这就是 c++ 多态性的体现。
ex.
#include <iostream>
using namespace std;
class Generation
{
public:
Generation() {}
Generation(int price) { this->p1 = price; }
~Generation() {}
virtual int getPrice() { cout << "G1 p1 " << p1 << endl; return p1; }//重点在于virtual关键字
private:
int p1;
};
class GenerationTwo:public Generation
{
public:
GenerationTwo(int price) { this->p2 = price; }
~GenerationTwo() {}
int getPrice() { cout << "G2 p2 " << p2 << endl; return p2; }
private:
int p2;
};
class GenerationThree:public Generation
{
public:
GenerationThree(int price) { this->p3 = price; }
~GenerationThree() {}
int getPrice() { cout << "G3 p3 " << p3 << endl; return p3; }
private:
int p3;
};
void compare(Generation *pf, Generation *pb)
{
if (pf->getPrice() > pb->getPrice())
{
cout << "front cost more than the back one" << endl;
}
else
{
cout << "front cost less than the back one" << endl;
}
}
int main(int argc, char const *argv[])
{
GenerationTwo gt2(20);
GenerationThree gt3(15);
compare(>2, >3);
return 0;
}
运行结果如下图所示,
总结下实现多态的条件:
- 有继承
- 有虚函数重写
- 用父类指针(引用)指向子类对象
理解为啥加了virtual
关键字能得到这样的效果?
运行时的实现依照指针的内容,编译时的实现根据指针的类型,声明为virtual
的函数会被绑定到运行时 (late bindling),则用父类指针指向子类对象,其函数调用子类virtual函数;而non-virtual
函数在编译器间就被绑定(early binding),则用父类指针指向子类对象,其函数调用父类non-virtual
函数。
虚析构函数
何为虚析构函数:在基类析构函数前加virtual
关键字。
为了解决什么问题:解决内存泄漏问题。
对于如上继承关系的类A,B,C,在 new 对象C 时,分别调用构造器A,B,C产生对于的内存,当使用父类指针释放子类内存时,实际上只释放了基类A构造函数开辟的内存,类B,C的内存并没有释放,造成内存泄漏。
void deletesomeone(A *base)
{
delete base; //并不会表现多态这种属性
}
void test()
{
C *t = new C;
deletesomeone(t);
}
重载重写重定义
重载发生在一个类之间,重写发生在两个类之间,虚函数重写发生多态,非虚函数重写也可称为重定义