首页 > 其他分享 ><九>理解虚继承和虚基类

<九>理解虚继承和虚基类

时间:2022-11-29 15:22:05浏览次数:42  
标签:继承 理解 派生类 int PA 基类 vbptr public

虚基类/抽象类

抽象类:有纯虚函数的类

虚继承
通过修饰继承方式, 如代码2是虚继承,被虚继承的类称为虚基类

虚继承派生类的内存布局方式
先是vbptr => 派生类的数据 =>基类的数据 ,
对比代码1和代码2,发现原本基类数据在前面,派生类数据在后面,但是在虚继承的时候
基类数据方式放到了后面,前面放了vbptr和派生类数据.
vbprt指向的是vbtable ,vbtable中存储的数据是偏移量, 是vbptr指针起始位置到基类的偏移量,见代码2和代码2后面的图片
通过偏移量可以找到基类数据,仔细对比代码1和代码2

vfprt/vbptr
vftabe/vbtable

代码1

class  A{

public:
     int ma;
protcted:
     int mb;
private:
     int mc;

}

//B继承 A,
class B : public A{
public:
     int md;
potected:
     int me;
private:
     int mf;
}

代码2 虚继承

#include <iostream>
using namespace std;

class  A{

public:
     int ma;

protected:
     int mb;
private:
     int mc;

};

//B继承 A,
class B : virtual public A{
public:
     int md;
protected:
     int me;
private:
     int mf;
};

int main(){

    return 0; 
        
}

代码3


#include <iostream>
using namespace std;

class  A{

public:
     int ma;
     virtual void show()
     {
     }
protected:
     int mb;
private:
     int mc;

};

//B继承 A,
class B : public A{
public:
     int md;
     virtual void show()
     {
     }
protected:
     int me;
private:
     int mf;
};

int main(){
   A *PA=new B();
   PA->show();
   return 0;        
}

代码4

#include <iostream>
using namespace std;

class  A{

public:
     int ma;
     virtual void show()
     {
     }
protected:
     int mb;
private:
     int mc;

};

//B继承 A,
class B : virtual  public A{
public:
     int md;
     virtual void show()
     {
     }
protected:
     int me;
private:
     int mf;
};

int main(){
   A *PA=new B();
   PA->show(); // 能正常调用B的show() 方法
   delete PA;  // 运行报错! 如下图
   return 0;        
}


vfptr/vbptr vbtable/vbtable 同时出现
当一个类有虚函数,那么就会生成vfptr,vfptr指向vftable,vftable中主要包含RTTI信息和虚函数地址信息
vbptr 专门为派生类从基类中虚继承用得,vbptr指向vbtable,vbtable中主要存储了vbptr到虚基类地址的偏移量

运行报错原因

PA->show();//正常
delete PA ;//运行报错
A *PA=new B(); 用基类指针指向派生类,问题:new B()返回的地址是vbptr起始地址?还是基类vfptr的起始地址?
基类指针指向派生类对象,PA指向的是基类的起始地址,即上图中vfptr起始地址,PA->show()能正常调用,因为
PA指向vfptr起始地址,直接可以将vfptr读取出来,但是释放内存的时候应该从vbptr地址开始释放,所以报错.

代码5

#include <iostream>
using namespace std;

class  A {

public:
	int ma;
        void operator delete(void *p) {
	    cout <<"A Operator Delete "<< p << endl;
	    free(p);
	}
	virtual void show()
	{
	}
protected:
	int mb;
private:
	int mc;

};

//B继承 A,
class B : virtual public A {
public:
	int md;
	void * operator new(size_t size) {
		void * p = malloc(size);
		cout << "class B operator new malloc Address=" << p << endl;
		return p;
	}
	virtual void show()
	{
	}
protected:
	int me;
private:
	int mf;
};

int main() {
	A *PA = new B();
	cout << PA << endl;
        delete PA;
	system("pause");
	return 0;
}

结合代码5中申请的内存地址,和返回的地址,类的内存结构,偏移量,等信息进行分析了解

如果代码5中改成如下

int main() {
        B b;
	A *PA = &b;
	system("pause");
	return 0;
}
b在栈上申请空间就不会有上面释放内存的错误(windows vc编译环境 ).

另外vfptr 是归属 基类还是派生类问题?
如果基类本身有虚函数的,那么vfptr归属基类,如果基类中没有虚函数,派生类有虚函数,那么vfptr归属派生类 如下图

vbtable中的偏移量是vbptr的起始地址到基类的偏移量

标签:继承,理解,派生类,int,PA,基类,vbptr,public
From: https://www.cnblogs.com/erichome/p/16934521.html

相关文章

  • 实验五 多态和继承
    实验内容:1.1.MachinePets.hpp:#include<iostream>#include<string>usingnamespacestd;classMachinePets{public:MachinePets(){}MachinePets(cons......
  • java最容易理解的旅行售货员问题
    packageNqueen;publicclasszuiduanluxian{/***旅行售货员问题--回溯法*@authorLican**/publicstaticclassBttsp{//建立一个javabean类而且是......
  • 对于证书的理解
    对于证书的理解证书类型-X.509证书PEMDER(二进制)--编码格式CRTCERPEM--拓展名用途及作用流程加密传输,例如https作用流程HTTPS使用的是对称......
  • C++多继承(多重继承)
    派生类都只有一个基类,称为单继承(SingleInheritance)。除此之外,C++也支持多继承(MultipleInheritance),即一个派生类可以有两个或多个基类。多继承容易让代码逻辑复杂、思路......
  • 深入理解css 笔记(完)
    一个网站,从看起来还可以,到看起来非常棒,差别在于细节。在实现了页面里某个组件的布局并写完样式之后,不要急着继续,有意识地训练自己,以挑剔的眼光审视刚刚完成的代码。如果增......
  • 实验5 继承和多态
    实验任务四:pets.hpp:#pragmaonce#include<iostream>#include<string>std::string;usingnamespacestd;classMachinePets{public:MachinePets(constst......
  • 实验五 继承和多态
    task4//pets.hpp#include<iostream>usingnamespacestd;classMachinePets{private:stringnickname;public:MachinePets(conststrings):n......
  • 路由守卫的理解(不完全,个人)
    1. 路由跳转几乎没有限制,只要触发就可以跳转,在一些条件下需要优化比如:一个需要登录的页面,在已经登录完成之后,就不应该能继续返回到登录页面或者未......
  • 深入理解Kubernetes 4A - Audit源码解析
    Overview本文是关于Kubernetes4A解析的第四章深入理解Kubernetes4A-Authentication源码解析深入理解Kubernetes4A-Authorization源码解析深入理解Kubernetes......
  • Chapter 3: Built-in Data Structures, Functions, and Files 个人理解与问题
    Chapter3:Built-inDataStructures,Functions,andFiles声明一下这里直接导入了Jupternotebooks的markdown笔记,不是很方便阅读3.1数据结构与序列3.1.1元组 ......