虚拟继承添加新的虚函数和没有添加新的虚函数的情况

1. 没重写也没增加虚函数。

#include <iostream>
using namespace std;
class Base
{
public:
virtual ~Base()
{
cout<<"Base::~Base()"<<endl;
}
virtual void f()
{
cout<<"Base::f()"<<endl;
}
public:
char c;
};
class Derived: virtual public Base
{
};
int main()
{
Base ba;
Derived de;
int a= sizeof(ba);//8:一个4个字节的vptr指针 +  一个字节的char + 3个字节的整体对齐
int b=  sizeof(de);
//12: 一个4个字节的偏移地址指针 + 一个4个字节的vptr指针(基类的) + 一个字节的char + 3个字节的整体对齐
cout<<"sizeof(Base)    : "<<a<<endl;
cout<<"sizeof(Derived) : "<<b<<endl;
return 0;
}

2.重写了虚函数,没新增加虚函数;

//2.1只重写了虚拟析构函数
/*
#include <iostream>
using namespace std;
class Base
{
public:
virtual ~Base()
{
cout<<"Base::~Base()"<<endl;
}
virtual void f()
{
cout<<"Base::f()"<<endl;
}
public:
char c;
};
class Derived: virtual public Base
{
public:
~Derived()
{
cout<<"Derived::~Derived()"<<endl;
}
public:
char cd;
};
int main()
{
Base ba;
Derived de;
int a= sizeof(ba);//8:一个4个字节的vptr指针 +  一个字节的char + 3个字节的整体对齐
int b=  sizeof(de);//12: 一个4个字节的偏移地址指针(0046C098) + 一个4个字节的vptr指针(基类的)  (0x0046c08c)  +  一个字节的char + 3个字节的整体对齐
cout<<"sizeof(Base)    : "<<a<<endl;
cout<<"sizeof(Derived) : "<<b<<endl;
return 0;
//奇怪的是:1 不关基类有没有数据成员变量,为什么虚基类的偏移指针在vptr之前,与 http://blog.sina.com.cn/s/blog_75a6dda00101bm31.html
//测试的不一样。
         //2 当子类和基类都有数据成员时,vbc_offset_pt还是在vptr之前,并且子类的数据数据成员在vptr和vbc_offset_pt之间,
//跟网址测试的不一样。
}
*/


/*
//2.2只重写了普通虚拟函数
#include <iostream>
using namespace std;
class Base
{
public:
virtual ~Base()
{
cout<<"Base::~Base()"<<endl;
}
virtual void f()
{
cout<<"Base::f()"<<endl;
}
public:
char c;
};
class Derived: virtual public Base
{
public:
void f()
{
cout<<"Derived::f()"<<endl;
}
};
int main()
{
Base ba;
Derived de;
int a= sizeof(ba);//8:一个4个字节的vptr指针 +  一个字节的char + 3个字节的整体对齐
        int b= sizeof(de);//12: 一个4个字节的偏移地址指针(0046C098) 一个4个字节的vptr指针(0x0046c08c) +  一个字节的char + 3个字节的整体对齐
       cout<<"sizeof(Base) : "<<a<<endl;cout<<"sizeof(Derived) : "<<b<<endl;return 0;
//奇怪的是为什么虚基类的偏移指针在vptr之前,与 http://blog.sina.com.cn/s/blog_75a6dda00101bm31.html
//测试的不一样。
}*/

//2.3重写了虚函数和虚拟析构函数
/*
#include <iostream>
using namespace std;
class Base
{
public:
virtual ~Base()
{
cout<<"Base::~Base()"<<endl;
}
virtual void f()
{
cout<<"Base::f()"<<endl;
}
virtual void g()
{
cout<<"Base::g()"<<endl;
}
public:
char c;
};
class Derived: virtual public Base
{
public:
~Derived()
{
cout<<"Derived::~Derived()"<<endl;
}
void g()
{
cout<<"Derived::g()"<<endl;
}
public:
char d;
};
int main()
{
Base ba;
Derived de;
int a= sizeof(ba);//8:一个4个字节的vptr指针 +  一个字节的char + 3个字节的整体对齐
int b=  sizeof(de);//16: 一个4个字节的偏移地址指针(0046C098) +4个字节的0+ 
//一个4个字节的vptr指针(基类的)  (0x0046c08c)  +  一个字节的char + 3个字节的整体对齐
cout<<"sizeof(Base)    : "<<a<<endl;
cout<<"sizeof(Derived) : "<<b<<endl;
return 0;
}
虚拟继承添加新的虚函数和没有添加新的虚函数的情况_第1张图片
*/

     综上所述:只要程序员自己定义子类时没有添加虚函数(当子类的数据成员有析构函数或者子类的父类有析构函数,注意不管是自己定义的还是合成的,当子类没有定义析构函数时,编译器会合成一个析构函数),子类的内存空间将是这样的:
(1)没有override没有添加 或者 只显示explicit override 一类虚函数(要么只override了虚拟析构函数,要么只override了普通虚拟函数):
         四个字节的bc_offset_pt(虚基类偏移指针)+[子类的数据成员[+对齐]+]+加上父类子对象(base subobject).
(2)显示explicit override 两类虚函数(虚拟析构函数和普通虚拟函数 都override了 ):
         四个字节的bc_offset_pt(虚基类偏移指针)+ [子类的数据成员[+对齐]+] +  4个字节的0 + 加上父类子对象(base subobject).

 3.添加新的虚函数,没有重写虚函数

//http://blog.sina.com.cn/s/blog_75a6dda00101bm31.html
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f()
{
cout<<"Base::f()"<<endl;
}
public:
char c;
};
class Derived: virtual public Base
{
public:
virtual void g()
{
cout<<"Derived::g()"<<endl;
}
public:
char cd;
};
int main()
{
Base ba;
Derived de;
int a= sizeof(ba);//8:一个4个字节的vptr指针 +  一个字节的char + 3个字节的整体对齐
int b=  sizeof(de);//16: 一个4个字节的vptr指针(自己的)  + 一个4个字节的偏移地址指针 + [ 子类自己的变量+]一个4个字节的vptr指针(父类的)   +  一个字节的char + 3个字节的整体对齐
cout<<"sizeof(Base)    : "<<a<<endl;
cout<<"sizeof(Derived) : "<<b<<endl;
return 0;
//不管子类或者基类中有没有数据变量,当子类自己定义了自己的虚函数时,虚基类的偏移指针紧接在子类vptr之后,子类数据之前,与 http://blog.sina.com.cn/s/blog_75a6dda00101bm31.html
//测试的一样。
}
4 添加虚函数,重写了虚函数
//4.重写了虚函数,添加新函数
//4.1 重写了虚拟析构函数
#include <iostream>
using namespace std;
class Base
{
public:
virtual ~Base()
{
cout<<"Base::~Base()"<<endl;
}
virtual void f()
{
cout<<"Base::f()"<<endl;
}
public:
char c;
};
class Derived: virtual public Base
{
public:
~Derived()
{
cout<<"Derived::~Derived()"<<endl;
}
virtual void g()
{
cout<<"Derived::g()"<<endl;
}
public:
char cd;
};
int main()
{
Base ba;
Derived de;
int a= sizeof(ba);//8:一个4个字节的vptr指针 +  一个字节的char + 3个字节的整体对齐
int b=  sizeof(de);//16: 一个4个字节的vptr指针(自己的) + 一个4个字节的偏移地址指针 +[子类的数据成员+] 一个4个字节的vptr指针(父类的)   +  一个字节的char + 3个字节的整体对齐
cout<<"sizeof(Base)    : "<<a<<endl;
cout<<"sizeof(Derived) : "<<b<<endl;
return 0;

//不管子类或者基类中有没有数据变量,当子类自己定义了自己的虚函数时,虚基类的偏移指针紧接在子类vptr之后,子类数据之前,与 http://blog.sina.com.cn/s/blog_75a6dda00101bm31.html
//测试的一样。


}
*/
/*
//4.2 重写普通虚函数
#include <iostream>
using namespace std;
class Base
{
public:
// virtual ~Base()
// {
// cout<<"Base::~Base()"<<endl;
// }
virtual void f()
{
cout<<"Base::f()"<<endl;
}
public:
char c;
};
class Derived: virtual public Base
{
public:
void f()
{
cout<<"Derived::f()"<<endl;
}
virtual void g()
{
cout<<"Derived::g()"<<endl;
}
public:
char cd;
};
int main()
{
Base ba;
Derived de;
int a= sizeof(ba);//8:一个4个字节的vptr指针 +  一个字节的char + 3个字节的整体对齐
int b=  sizeof(de);//16: 一个4个字节的vptr指针(自己的) +一个4个字节的偏移地址指针 + 一个4个字节的vptr指针(自己的)   +  一个字节的char + 3个字节的整体对齐
cout<<"sizeof(Base)    : "<<a<<endl;
cout<<"sizeof(Derived) : "<<b<<endl;
return 0;

//不管子类或者基类中有没有数据变量,当子类自己定义了自己的虚函数时,虚基类的偏移指针紧接在子类vptr之后,子类数据之前,与 http://blog.sina.com.cn/s/blog_75a6dda00101bm31.html
//测试的一样。
//子类的vptr指向的虚函数表中只有自己添加的新的虚函数的地址,父类的vptr中指向的虚函数表中有子类没有改写的虚函数,和子类override的虚函数
}
*/

    综合所述:只要子类添加了自己的虚函数,子类就会添加一个vptr(虚函数指针),指向的虚函数表中只包含自己添加的虚函数;然后接着是四个字节的vbc_offset_pt,[子类的数据],父类的数据(父类的vptr和父类的数据),其中父类的vptr指向的虚函数表中含有子类没有override的虚函数和子类override的虚函数,注意,如果父类中有虚拟析构函数,不管子类有没有override,在父类的虚函数表中析构函数都是指向子类的。

你可能感兴趣的:(虚拟继承添加新的虚函数和没有添加新的虚函数的情况)