一段代码搞明白c++虚函数相关

code tells;
之前花了半个下午搞得,本来都有点舍不得放出来.缺失的部分是多重继承相关的,内容我写到书上了,要是看的人多我就挪过来.

#include <algorithm>
#include <cstdio>
#include <iostream>

class Base1
{
public:
void b1f1()
{
std::cout << "Base1::b1f1()" << std::endl;
}
virtual void vb1f1()
{
std::cout << "Base1::vb1f1()" << std::endl;
};
};
class Base2
{
public:
virtual void vb2f1()
{
std::cout << "Base2::vb2f1()" << std::endl;
};
virtual void vb2f2()
{
std::cout << "Base2::vb2f2()" << std::endl;
};
};

class Driven1 : public Base1
{
public:
virtual void d1()
{
std::cout << "Driven1::d1()" << std::endl;
};
};
class Driven2 : public Base1, Base2
{
public:
virtual void d2()
{
std::cout << "Drivend::d2()" << std::endl;
};
};
class DrivenDriven1 : public Driven2, Driven1
{
public:
virtual void dd1()
{
std::cout << "DrivenDriven1::dd1()" << std::endl;
};
};
using namespace std;

int main( int argc, char** argv )
{
//内存布局相关
if ( 0 ) {
Base1 base1;
cout << "sizeof Base1 : " << sizeof( base1 ) << endl;
Base2 base2;
cout << "sizeof Base2 : " << sizeof( base2 ) << endl;
Driven1 drive1;
cout << sizeof( drive1 ) << endl;
Driven2 d2;
cout << "sizeof Driven2 : " << sizeof( d2 ) << endl;
DrivenDriven1 dd1;
cout << "sizeof DrivenDriven1 : " << sizeof( dd1 ) << endl;
}

Base1* b1 = nullptr;
Base2* b2 = nullptr;
//虚函数相关
if ( 1 ) {
b1->b1f1(); //正常运行,因为和对象无关和类有关 这个函数里也不涉及成员变量操作
// b1->vb1f1();//段错误,因为需要虚函数指针,虚函数指针是被对象拥有的,这里还没创建对象
// b2->vb2f1();
// b2->vb2f2();
}

b1 = new Base1;
b2 = new Base2;
//都正常运行了
if ( 1 ) {
b1->b1f1();
b1->vb1f1();
b2->vb2f1();
b2->vb2f2();
std::cout<<"--------------------------"<<std::endl;
}
if ( 1 ) {
auto temp = ( Base1* )b2;
temp->b1f1(); // Base1::b1f1() 因为普通函数和类相关,编译器现在认为他的类是Base1调用这个类的这个函数
temp->vb1f1(); // Base2::vb2f1() 虚函数和对象所拥有的虚函数指针有关,强制类型转化并不会改变虚函数指针,所以这个对象的虚函数指针还是指向Base2的那些函数的.
//并且编译器内部对于虚函数表的查找方式不是按照字符串匹配,而是按照索引.
//所以句代码的实际意义是:调研这个对象的虚函数表的x索引(但是这个索引是通过vb1f1和Base1的关系得到的,索引是类的属性,在编译时确定)位置的函数.
auto temp2 = ( Base2* )b1;
cout << "temp2->vb2f1()调用函数的地址 : " << ( int* )*( int* )&temp2 << endl; // +1的1就是索引
temp2->vb2f1(); // Base1::vb1f1()
cout << "temp2->vb2f2()调用函数的地址 : " << ( int* )*( int* )&temp2 + 1 << endl; // +1的1就是索引
//temp2->vb2f2(); //这个地方还没函数,所以段错误 //段错误
// Base1::b1f1()
// Base2::vb2f1()
// Base1::vb1f1() //到这里是正常输出的
// Base1::b1f1() //下面的包括这行是因为段错误多打印的.为什么会打印这些呢?
// Base2::vb2f1()
// Base1::vb1f1()
std::cout<<"--------------------------"<<std::endl;
}
if ( 1 ) {
cout << "类对象地址:" << &b1 << endl;
cout << "虚函数表地址: " << ( int* )*( int* )&b1 << endl;
cout << "虚函数1地址:" << ( int* )*( int* )&b1 << endl;
cout << "虚函数2地址:" << ( int* )*( int* )&b1 + 1 << endl;
cout << "虚函数3地址:" << ( int* )*( int* )&b1 + 2 << endl;
printf( "Base1函数b1f1地址:%p\n", &Base1::b1f1 ); //实际的函数位置
printf( "Base1函数vb1f1地址:%p\n", &Base1::vb1f1 ); //虚函数指针的相对位置,比如第一个是x1 第二个是x9 他们的索引差就是 (9-1)/虚函数指针大小 =1
printf( "Base2函数vb2f1地址:%p\n", &Base2::vb2f1 );
printf( "Base2函数vb2f2地址:%p\n", &Base2::vb2f2 );
}
// system("pause");
return 0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值