摘要:本文主要向大家介绍了C++语言虚函数实现机制以及类继承中的内存分布,通过具体的代码向大家展示,希望对大家学习C++语言有所帮助。
本文主要向大家介绍了C++语言虚函数实现机制以及类继承中的内存分布,通过具体的代码向大家展示,希望对大家学习C++语言有所帮助。
c++为了兼容c保留了struct类型,但是c++中的struct和c有明显的区别,c++中的struct可以继承,可以有成员函数,但是在c中却不行,在c++中struc和class更相似(还是有一些区别的,这里不再叙述),c中struct的内存分布很简单,那么c++中的class(struct)是怎么样的呢?
[cpp] view plain copy 1. #include 2. using namespace std; 3. 4. class BaseClass 5. { 6. int a; 7. int b; 8. public: 9. void myfunc() {} 10. } 11. 12. int main() 13. { 14. std::cout << "size = " << sizeof(BaseClass) << std::endl; 15. rturn 0; 16. }
这里很简单运行结果为8,这里有一点要注意的就是static 变量存放在静态存储区,不占用该类的存储空间。这里还有一种特殊情况就是当c++为空类(可没有成员变量的),这时候c++为了确保每个对象有一个唯一的地址,给空类分了一个字节的大小来占位,对于此很多人很不理解,我们可以反向思维如果此时大小为0,那么一个类数组岂不是不占用空间了。
[cpp] view plain copy 1. #include 2. using namespace std; 3. 4. class BaseClass 5. { 6. int a; 7. int b; 8. char c; 9. 10. public: 11. virtual void myfunc() {} 12. } 13. 14. int main() 15. { 16. std::cout << "size = " << sizeof(BaseClass) << std::endl; 17. rturn 0; 18. }
这里的结果似乎有点意思(测试环境:mac 64),运行结果24,解释一下,首先两个int占8字节,最后就是这里的虚函数,这里稍微谈一下c++的虚函数,c++运行时多态是基于c++虚函数的,为了实现当父类指针指向一个自类对象时,根据对象的类型(子类还是父类)来执行相应的函数,c++在类中用一个int指针(官方称之为虚函数表,实际上是一个int数组,里面保存了所有的虚函数地址,注:以函数指针的形式保存),因此这个虚函数表的地址(int 指针)占用8字节,共24个字节。
[cpp] view plain copy 1. #include 2. using namespace std; 3. 4. class BaseClass 5. { 6. public: 7. int a; 8. int b; 9. char c; 10. 11. public: 12. virtual void myfunc() {} 13. }; 14. 15. class ChildClass : public BaseClass 16. { 17. public: 18. int d; 19. public: 20. virtual void myfunc() {} 21. }; 22. 23. int main() 24. { 25. std::cout << "BaseClass size = " << sizeof(BaseClass) << std::endl; 26. std::cout << "ChildClass size = " << sizeof(ChildClass) << std::endl; 27. rturn 0; 28. }
这里运行结果一样都是24,当我点击运行看到运行结果的时候我的第一反应就是,我擦,系统出错了,子类比父类多了一个int竟然大小一样,我愣了一下,仔细分析了一下,才发现其中的奥秘,首先子类24,以上已经分析过了,这里之所以没有变化是因为子类把继承自父类的char c和自己的int d,合并成了5个字节然后做了8字节对齐,而子类是一个char 一个字节做了8字节对齐。
这里可以看到,子类不但继承了父类的成员变量,而且继承了父类的的虚函数表,这时候问题来了,子类和父类怎么实现多态呢。
[cpp] view plain copy 1. #include 2. using namespace std; 3. 4. class BaseClass 5. { 6. public: 7. int a; 8. int b; 9. public: 10. virtual void myfunc() {printf("BaseClass myfunc \n");} 11. virtual void myfunc1() {printf("BaseClass myfunc1 \n");} 12. }; 13. 14. class ChildClass : public BaseClass 15. { 16. public: 17. int d; 18. public: 19. virtual void myfunc() {printf("ChildClass myfunc \n");} 20. virtual void myfunc3() {printf("ChildClass myfunc3 \n");} 21. }; 22. 23. int main() 24. { 25. BaseClass *a = new BaseClass; 26. a->myfunc(); 27. a->myfunc1(); 28. printf("**************"); 29. 30. BaseClass *b = new ChildClass; 31. a->myfunc(); 32. a->myfunc1(); 33. // b->myfunc3(); 34. // int myd = b->d; 35. 36. printf("**************"); 37. ChildClass *c = new BaseClass; 38. a->myfunc(); 39. a->myfunc1(); 40. rturn 0; 41. }
运行结果:
BaseClass myfunc
BaseClass myfunc1
**************
ChildClass myfunc
BaseClass myfunc1
**************
ChildClass myfunc
BaseClass myfunc1
ChildClass myfunc3
当创建父类对象时将虚表指针指向父类的虚表,当创建子类对象时,将虚表指针指向子类的虚表。所以当我们用一个父类指针指向一个子类对象时,通过该指针调用一个虚函数时,其实此时的虚表指针指向了子类的虚表,那么我们就会调用子类相应的虚函数了,当然这只是当子类重写了父类的虚函数,这时候就会有多态的机制,因为此时子类的虚函数表中指向的是自己的函数实现。如果我们子类没有实现父类的虚函数呢,因为我们继承了父类的虚函数表,所以我们回去调用父类的函数。
还有一点要注意的就是当我们用一个父类指针指向一个子类对象时,能实现多态的必须是父类中有的,因为当我们子类继承了父类的成员函数和变量但是父类并没有子类的(上面注释掉的两行是错误的,注:这里有一个疑问,第二行注释我能理解,父类并没有子类的成员变量d,但是按我的理解此时调用虚函数时,应该指向了子类的虚函数表,此时虚函数表是子类的,为什么不能调用自己的myfunc3呢?求解....)
本文由职坐标整理并发布,了解更多内容,请关注职坐标编程语言C/C+频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号