C++ 继承和虚基类 初探

写麻将客户端时,遇到这么一个问题:需要将一个String类型转换为byte类型,然后通过广播发送出去。

Java的实现方法如下:

String s = "test";

byte b[] = s.getByte();//字符串转byte

s = new String(b);//byte转字符串

由这个问题,联想到,C++中的类在内存中是如何存储的呢,于是开始动手写代码测试,代码如下:

1.

class class_a
{
public:
int a;
class_a()
{
a=1;
}
};
该实例占4字节 说明实例中不包含构造函数的地址
2.
class class_b
{
public:
int a;
 
class_b(){};
private:
void fun_1(){};
};
class class_c
{
public:
int a;
class_c(){};
void fun_1(){};
};
两个类的实例都是占4字节 说明不管是public类型还是private类型的成员函数,其地址均不包含在实例内
3.
class class_d
{
public:
int a;
virtual void fun_1(){};
};
 
class class_d
{
public:
int a;
virtual void fun_1(){};
virtual void fun_2(){};
};
 
 
这两个类的实例占8字节,而且,不管类中的虚函数个数为多少,均占8个字节。
这个现象就证实了“虚表”这个概念:一个类的虚函数的地址是保存在一个虚表中的,而虚表的表头则存储在类的每个实例中。
下面来验证多重继承时,实例中虚表的个数(比如,是不是如果一个类继承了另一个类,虚表的个数就变成了2个呢?),测试代码和输出如下:(继承关系为:class_2、class_3继承class_1,class_4继承class_3,class_5继承class_2和class_3)
 //有虚函数的继承 

class class_1//实例占8字节
{
public:
int a;
virtual void fun_1(){};
class_1()
{
a = 1;
printf("class_%d 实例化\r\n",a);
}
};
class class_2 : class_1//实例占12字节
{
public:
int a;
void sub_fun1(){};
class_2()
{
a=2;
printf("class_%d 实例化\r\n",a);
}
};
class class_3 : class_1//实例占12字节
{
public:
int a;
virtual void fun_1(){};
class_3()
{
a=3;
printf("class_%d 实例化\r\n",a);
}
};
class class_4 : class_3//实例占16字节
{
public:
int a;
virtual void sub_fun_1(){};
class_4()
{
a = 4;
printf("class_%d 实例化\r\n",a);
}
};
class class_5: class_3,class_2
{
public:
int a;
virtual void sub_fun_1(){};
class_5()
{
a = 5;
printf("class_%d 实例化\r\n",a);
}
};


//没有虚函数的继承
class class_6
{
public:
int a;
class_6()
{
a=6;
printf("class_%d 实例化\r\n",a);
}
};//实例占四个字节
class class_7:class_6
{
public:
int a;
class_7()
{
a=7;
printf("class_%d 实例化\r\n",a);
};
};//实例占八个字节


int _tmain(int argc, _TCHAR* argv[])
{
int *i;
class_1 *p1 = new class_1();
int t1 = sizeof(*p1);
i=(int*)p1;
printf("size %d content of p1: %d %d \r\n",t1,i[0],i[1]);
class_2 *p2 = new class_2();
int t2 = sizeof(*p2);
i=(int*)p2;
printf("size %d content of p2: %d %d %d \r\n",t2,i[0],i[1],i[2]);
class_3 *p3 = new class_3();
int t3 = sizeof(*p3);
i=(int*)p3;
printf("size %d content of p3: %d %d %d \r\n",t3,i[0],i[1],i[2]);
class_4 *p4 = new class_4();
int t4 = sizeof(*p4);
i=(int*)p4;
printf("size %d content of p4: %d %d %d %d \r\n",t4,i[0],i[1],i[2],i[3]);
class_5 *p5 = new class_5();
int t5 = sizeof(*p5);
i=(int*)p5;
printf("size %d content of p5: %d %d %d %d %d %d %d \r\n",t5,i[0],i[1],i[2],i[3],i[4],i[5],i[6]);
class_6 *p6 = new class_6();
int t6 = sizeof(*p6);
i=(int*)p6;
printf("size %d content of p6: %d\r\n",t6,i[0]);
class_7 *p7 = new class_7();
int t7 = sizeof(*p7);
i=(int*)p7;
printf("size %d content of p7: %d %d\r\n",t7,i[0],i[1]);
system("pause");
return 0;
}


结果分析:


可以看到,在class_5的实例化过程中,class_1实例化了两次。

从这个结果中我们便可以看出虚基类的用处是什么了。此时没有用虚基类,如果我们要调用class_1实例中的fun_1,编译器便不能确定我们是要调用哪个实例的成员,然后会报错——“fun_1”不明确。如图


当然,如果在class_5中重写虚函数,则不会报错。

参考:

RTTI、虚函数和虚基类的实现方式、开销分析及使用指导 http://www.baiy.cn/doc/cpp/inside_rtti.htm

求一个类的sizeof应该考虑的问题 http://blog.sina.com.cn/s/blog_728161840100u2ib.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值