C++ 虚函数、多态

所谓多态就是相同的调用,得到不同的结果。一种调用多种状态。
实现多态必须满足三个条件:1、有子类继承 2、有虚函数重写 3、要有父类指针(父类引用)指向子类对象

class Parent {
public:
	Parent(int a = 0) {
		this->a = a;
	}
	//第一个动手脚的地方,编译器应该对这个虚函数,特殊处理
	virtual void print() {
		printf("这是父类-------a=%d\n", this->a);
	}
protected:
private:
	int a;
};

class Child:public Parent {
public:
	Child(int b) {
		this->b = b;
	}
	virtual void print() {     //这里面写不写virtual关键字都是虚函数
		printf("这是子类-------b=%d\n", this->b);
	}
protected:
private:
	int b;
};

void howToPrint(Parent * pBase) {
	pBase->print();
	//这个地方也是一个动手脚的地方2 传来一个子类对象,调用子类的函数,传来一个父类对象,调用父类的函数
	//判断,pBase,增加判断的条件,===》应该是在不知道的情况增加判断条件。编译器提前加条件
	//handle....
}

void main_base() {
	Child c(20);//
	//Parent p1;   //在这个地方,编译器已经提前布局,给函数有虚函数表的对象,提前加了vptr指针
	howToPrint(&c);//调用了子类的print()函数。
	//howToPrint(&p1);
}

说明:
1、通过虚函数表指针vptr调用重写函数是在程序运行时进行的,因此需要通过寻址操作才能确定了调用的函数,在效率上,虚函数的效率要低很多
2、出于效率考虑,没有必要将所有成员函数都声明为虚函数

如果在父类的构造函数中调用虚函数,有没有发生多态呢?也就是会调用子类的print,还是父类print.

class Parent {
public:
	Parent(int a = 0) {
		this->a = a;
		print();   //在这里不会发生多态
	}
	virtual void print() {
		printf("这是父类-------a=%d\n", this->a);
	}
protected:
private:
	int a;
};

这就要弄清一个执行顺序。
子类对象初始过程:
1、首先调用父类的构造函数,子类的vptr(虚函数表指针)被初始化,指向父类虚函数表
2、当执行完毕父类的构造函数,子类的vptr指针被重新赋值,指向子类虚函数表。
子类虚函数表指针的初始化时分步骤完成的。
所以在父类构造函数中调用虚函数时,不会发生多态。

那么如何证明vptr指针存在呢?

class A {
public:
	virtual void print() {
		printf("ddddd\n");
	}
protected:
private:
	int b;
};
void main() {
	printf("AA---->%d\n", sizeof(A));
	A a;
	cout << sizeof(a) << endl; //如果没有虚函数大小为4,加上虚函数表指针大小为8
}

构造函数可以是虚函数吗?

不可以,对象通过构造函数来分配内存,以及给vptr赋初值,如果构造函数是虚函数话的,顺序就矛盾了。

析构函数虚函数的应用场景

析构函数可以是虚函数,而且要尽量是虚函数,

class Parent{
public:
	~Parent(){
		if(p!=NULL){
			free(p);
			p==NULL;
		}
	}
private:
	int a;
	char * p;
}
class Child:public Parent{
public:
	~Child(){
		if(b!=NULL){
			free(b);
			b=NULL;
		}
	}
private:
	char * b;
}
void howToDelete(Parent *p) {
	delete p;//这个时候,删除p如果父类虚构函数是虚函数的话,也会调用子类的析构函数,否则只调用父类的析构函数,产生内存泄漏
}

在父类中声明虚构函数的原因:
通过父类指针,把子类的析构函数都执行一遍,这又是在利用未来的代码。

什么是纯虚函数呢?

C++规定virtual 返回类型 函数名() = 0;为纯虚函数。把含有纯虚函数的类称为抽象类,抽象类不能实例化,插入一点(我记得java中为了防止抽象类的实例化,将构造函数设置为私有,类外部不能调用),为什么不能实例化呢?因为方法只声明没定义,编译器不知道如何做。但是可以定义一个指向抽象类的指针。
c++中没有interface接口关键字,c++语言出现的比较早,没有java先进。
抽象类就像一个说明书,或者说开发规范,给各个厂家或者开发者,你要实现这个虚函数,我通过new 你的子类对象,就可以调用你的实现的方法。

猜你喜欢

转载自blog.csdn.net/Raven_csdn/article/details/88667687