标签:内存数据 虚基类 mem int 解决 类的声明 多个 c++ nbsp
当某类的部分或全部直接基类是从另一个共同基类派生而来时,在这些直接基类中从上一级共同基类继承来的成员就拥有相同的名称。在派生类的对象中,这些同名数据成员在内存中同时拥有多个拷贝,同一个函数名会有多个映射。我们可以使用作用域分辨符来惟一标识并分别访问他们,也可以将共同基类设置为虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样就解决了同名成员的惟一标识问题。
虚基类的声明是在派生类的定义过程中进行的,语法形式:
class 派生类名:virtual 继承方式 基类名
在多继承的情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。声明了虚基类之后,虚基类的成员在进一步派生过程中和派生类一起维护同一个内存数据拷贝。
如:
有一个基类B0,声明了数据成员nV和函数fun,由B0公有派生产生了类B1和B2,与前一个例子不同的是派生时声明了B0为虚基类,再以B1、B2作为基类共同公有派生了新类D1,在派生类中我们不再添加新的同名成员,这时的D1类中,通过B1、B2两条派生路径继承来的基类B0中的成员nV和fun只有一份拷贝。
使用了虚基类之后,在派生类D1中只有唯一的数据成员nV和fun。在建立D1类对象的模块中,直接使用”对象名.成员名“方式就可以惟一标识和访问这些成员。
如:
#include<iostream>
using namespace std;
class B0
{
public:
int nV;
void fun(){cout<<"Member of B0"<<endl;}
};
class B1:virtual public B0 //B0为虚基类,派生了B1类
{
public:
int nV1;
};
class B2:virtual public B0//B0为虚基类,派生了B2类
{
public:
int nV2;
};
class D1:public B1,public B2 //派生类D1定义
{
public:
int nVd;
void fund(){cout<<"Member of D1"<<endl;}
};
int main()
{
D1 d1;
d1.nV=2;
d1.fun();
getchar();
}
结果:
Member of B0
3、虚基类及其派生类构造函数
如果虚基类声明有非默认形式的(即带形参的)构造函数,并且没有声明默认形式的构造函数,事情就比较麻烦了。这时,在整个继承关系中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化列表中列出对虚基类的初始化。
如:
#include<iostream>
using namespace std;
class B0
{
public:
B0(int n){nV=n;}
int nV;
void fun(){cout<<"Member of B0"<<endl;}
};
class B1:virtual public B0 //B0为虚基类,派生了B1类
{
public:
B1(int a):B0(a){}
int nV1;
};
class B2:virtual public B0//B0为虚基类,派生了B2类
{
public:
B2(int a):B0(a){}
int nV2;
};
class D1:public B1,public B2 //派生类D1定义
{
public:
D1(int a):B0(a),B1(a),B2(a){}
int nVd;
void fund(){cout<<"Member of D1"<<endl;}
};
int main()
{
D1 d1(1);
d1.nV=2;
d1.fun();
getchar();
}
建立D1类对象d1时,通过D1类的构造函数的初始化列表,不仅直接调用了虚基类构造函数B0,对从B0继承的成员nV进行了初始化,而且还调用了直接基类B1和B2的构造函数B1()和B2()的初始化列表中也都有对基类B0的初始化。这样岂不是从虚基类继承来的成员nV初始化了三次?其实c++编译器的处理方式是,在上面程序中,建立对象d1时,D1就是最远派生类。建立一个对象时,如果这个对象中含有虚基类继承来的成员,则虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。而且,只有最远派生类的构造函数会调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用都自动被忽略。
标签:内存数据 虚基类 mem int 解决 类的声明 多个 c++ nbsp
原文地址:http://www.cnblogs.com/gary-guo/p/6247036.html