继承和多态

继承

单继承

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(&gt2, &gt3);

	return 0;
}

运行结果如下图所示,
继承和多态
总结下实现多态的条件:

  1. 有继承
  2. 有虚函数重写
  3. 用父类指针(引用)指向子类对象

理解为啥加了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); 
}

重载重写重定义

重载发生在一个类之间,重写发生在两个类之间,虚函数重写发生多态,非虚函数重写也可称为重定义