c++ day14 多态原理的探究

  • c++中多态的实现原理
  • 1.当类中声明虚函数时,编译器会在类中生成一个虚函数表
  • 2.虚函数就是一个存储类成员函数指针的数据结构
  • 3.虚函数表是由编译器自动生成和维护的
  • 4.virtual成员函数会被编译器放入虚函数表中
  • 5.存在虚函数时候,每个对象都有一个指向虚函数表的指针(vptr指针)
  • 证明一下vptr指针存在
#include <iostream>
using namespace std;
//多态成立的三个条件
//要有继承
//要有虚函数重写
//父类指针指向子类对象
class Parent{
public:
	Parent(int a=0){
		this->a  =a;
	}
	virtual void print(){  //写virtual关键字,c++会特殊处理
		//传来子类对象执行子类函数  传来父类对象执行父类的函数
		cout<<"父类构造函数"<<a<<endl;
	}
protected:
private:
	int a ;
};
class Child :public Parent{
public:
	Child(int a=0,int b =0):Parent(a){
		this->b  =b;
	}
	void print(){
		cout<<"子类构造函数"<<b<<endl;
	}
protected:
private:
	int b ;
};
void howToPlay(Parent *p){
	p->print();//多态
}

void main(){
	Parent p1;//用类定义对象的时候 c++编译器会在对象中添加vptr指针
	//做成了虚函数表
	//其实c++编译器不需要区分是子类对象还是父类对象,之区分virtual
	//根据虚函数表再找函数入口地址,通过这样的方法实现迟绑定
	//在运行这块代码的时候编译器才去判断该执行哪个函数
	Child c1;
	howToPlay(&p1);
	howToPlay(&c1);

	cout<<"hello"<<endl;
	system("pause");
	return ;
}

  • 证明一下vptr指针存在
#include <iostream>
using namespace std;

class Parent1{
public:
	Parent1(int a=0){
		this->a  =a;
	}
	 void print(){  
		cout<<"父类构造函数"<<a<<endl;
	}
protected:
private:
	int a ;
};
class Parent2{
public:
	Parent2(int a=0){
		this->a  =a;
	}
	virtual void print(){  
		cout<<"父类构造函数"<<a<<endl;
	}
protected:
private:
	int a ;
};


void main(){
	Parent1 p1;
	printf("%d\n",sizeof(Parent1));
	printf("%d\n",sizeof(Parent2));


	cout<<"hello"<<endl;
	system("pause");
	return ;
}

  • 构造函数中能调用虚函数,实现多态么?
  • 当执行父类的构造函数时候,子类的vptr指针指向父类的虚函数表
  • 当父类的构造函数运行完毕后,会把子类的vptr指针指向子类的虚函数表
  • 结论,子类的vptr指针分布完成
  • 子类的vptr指针是分步初始化的
  • 是否可以把所有的函数都声明为虚函数呢?
  • 答案是可以的,但是会严重影响效率。因为会有大量的寻址操作,不建议给每一个成员都加上virtual
  • 其实虚函数的实现就是函数指针做参数来实现的,实现了一个回调的效果

  1. 父类指针和子类指针步长不一样的情况

指针++其实是根据数组数组单位的size来的


#include <iostream>
using namespace std;
//构造函数中调用虚函数能发生多态么
class Parent{
public:
	Parent(int a=0){
		this->a  =a;
		print();
	}
	virtual void print(){  
	
		cout<<"父类构造函数"<<a<<endl;
	}
protected:
private:
	int a ;
};
class Child :public Parent{
public:
	/*
	Child(int a=0,int b =0):Parent(a){
		this->b  =b;
		print();
	}*/
	Child(int b =0):Parent(0){
		this->b  =b;
		print();
	}
	void print(){
		cout<<"子类构造函数"<<b<<endl;
	}
protected:
private:
	int b ;
};
void howToPlay(Parent *p){
	p->print();
}

void main(){
	//Child c1;两个带参构造出现二义性
	Child c1;
	Child *cc = NULL;;
	Parent *pp = NULL;
	Child array[] = {Child(1),Child(2),Child(3)};
	pp = array;//父类指针指向子类对象
	cc = array;
	pp->print();//父类指针访问函数
	cc->print();//子类指针指向函数

	pp++;
	cc++;
	pp->print();
	cc->print();//多态

	cout<<"hello"<<endl;
	system("pause");
	return ;
}

//子类指针步长比父类长,子类和父类指针步长不一样
//可以进行多态的调用,但是和值的步长是两个不同的概念

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值