C++类详解
来源:互联网 发布:淘宝运费险什么意思 编辑:程序博客网 时间:2024/05/17 01:54
类详解:
一,类在内存中的存放方式
<1>不含成员变量的类
class A{ //sizeof(A) == 1 //空类具有1个字节的唯一标识,用于区别不同的空类};class B{ public: //sizeof(B) == 1,其他同上 //成员函数不占用任何对象内存空间 B(){} ~B(){}};class C{ public: //sizeof(C) == 4 //拥有虚函数的类则会创建一个虚表指针 C(){} virtual ~C(){}};
<2>静态变量&常量。
class cA{public: int a; int b; static int z; //const int e = 0;这样初始化时错误的,类常量只能使用构造函数 const int e;public: cA(int pe):e(pe) { } static void function1() { }};
内存结构如下
由此可以知道:
(1)类常量只能在构造函数中赋值。
(2)静态函数和静态变量不占用类内存空间。
<3>含成员变量的类。
(1)无虚函数类
class A{ public: int a; int b; public: void function1(){}};
内存排列输出如下:
由此可以知道,可以看见类的成员函数并不会占内存空间,而类的成员变量则会按顺序储存。
(PS,假如类的成员变量涉及多种类型,则需要进行字节对齐)。
(2)含虚函数类
class A{ public: int a; int b; public: void function1(){} virtual void fuction2(){}};
内存排列输出如下:
由此可以知道:
(1),当存在虚函数时,在类内存的开始处(偏移值为0时),会保存一个虚表指针,然后再按顺序存放成员变量。
(2),接下来是虚表,它记录了一张虚表,该虚表表示对应的虚指针在内存中的分布,左边的0表示第一个虚函数的位置。
编译器是在构造函数创建此虚表指针以及虚表的。
问:那么编译器是如何利用虚表指针和虚表实现多态的呢?
答:当创建一个含有虚函数的父类的对象时,编译器在对象构造时将虚表指针指向父类的虚函数;同样,当创建子类的对象时,编译器在构造函数里将虚表指针(子类只有一个虚表指针,它来自父类)指向子类的虚表(这个虚表里面的虚函数入口地址是子类的)。
(3)继承后的类
class A{ public: int a; int b; public: void function1(){} virtual void fuction2(){}};class B:public A{ public: int c; public: virtual void function2(){}//重写 void function3(){} //属于派生类的成员函数}
内存排列输出如下:
由此可以知道:
(1)内存排列继续沿用cA的内存结构,然后在末尾增加新的成员变量内存空间。
(2)虚函数表使用的是cB自己的虚表。
(4)带有自己虚函数及没重载父类虚函数的的派生类。
class B:public A{ public: int c; public: virtual void function2(){}//重写 virtual void function3(){} //属于派生类的成员函数}
内存排列输出如下:
由此可知道:
(1)没有重载父类虚函数,则虚函数表使用的是父类的虚函数。
(2)新增的派生类虚函数,会加进派生类的虚表。
(5)多继承派生类的内存结构。
class C:public A{ public: int c; public: virtual void function2(){}//重写 virtual void function3(){} //属于派生类的成员函数}class D:public C,public B{}
类D的内存结构如下:
由此可知道:
(1)多重继承会按照继承的顺序将虚表指针及成员变量按顺序排列。
(2)将会记录所有直接父类的虚表,因此我们调用function2和function3时必须使用对应的父类标记调用。
cD *tmp = new cD(); tmp->function2();//这样编辑器会提示函数不明确,不能编译 tmp->B::function2();//这样写能正确调用
假如我修改类D重载B,C的function3,将会将屏蔽B,C的虚函数:
class D:public C,public B{ //属于派生类的成员函数 virtual void function3() { } }
则在虚表部分会有相应的修改
(6)虚继承。
class D:virtual public C,virtual public B{ //属于派生类的成员函数 virtual void function3() { } }
内存结构如下:
二,类引申出来的问题
(1)指向类的指针在不实例化的情况下,调用类的成员函数有什么结果,虚函数呢?
答:由类的内存结构我们可以知道,类的成员函数(非虚函数,也包含构造函数与析构函数)是储存在一个固定的位置,和类的实例化无关(类的实例化只申请类成员变量空间和绑定虚函数表)。
因此类没实例化之前,类的成员变量和虚函数表没有初始化,但是类的成员函数因为与类的实例化无关,所以可以正常调用。但是此时请注意,在类的成员函数中假如使用到类的成员变量,程序将会运行时出错,同理,调用虚函数时也会出错。
(2)在类的构造函数中能调用delete this吗,会出现什么结果?
答:此问题主要考察类调用函数的原理,由问题(1)我们可以知道,类不实例化时还是能调用自己的成员函数的(但函数不能操作成员变量),其实类在调用成员函数时就是将自己的this指针作为参数传进成员函数,因此成员函数能随时使用this中指向的已被创建出来的成员变量,因此,由于构造函数也是成员函数,所以在构造函数是可以使用delete this的,但是delete后该变量的实例化将会被消除,后续就不能使用了。
参考文档:
c++ 类成员函数内删除this指针
http://blog.csdn.net/fridayzhu/article/details/32396205
C++类内存分布
http://www.cnblogs.com/jerry19880126/p/3616999.html
声明:
该文仅作学习与记录之用,欢迎技术纠错和讨论;
非技术性言论皆为一家之谈,如有不同意见请坚持己见;
如有雷同可能为学习汝之所得,请各位巨人的肩膀还请继续空出位置。
- 【c++】类&对象详解
- C string类c_str() 详解
- c++string类详解收集
- C++bitset类详解收集
- 【C++】类中virtual详解
- 【C/C++】:sizeof详解
- C/C++-----static详解
- C/C++extern详解
- C#Monitor类 Lock Mutex类详解
- 【C++】c++类的构造函数详解
- c++string类的常用方法详解
- 【C++】 类中virtual详解2
- static详解(c/c++)
- C/C++static关键字详解
- [C/C++] 指针(详解)
- C/C++static关键字详解
- C++/C链接过程详解
- C/C++static、const详解
- 指针之动态分配内存
- 字符串反转 转换大小写的三种方法
- wireshark抓到tcp包大于mss的包
- 重装电脑遇到的问题(三)
- C#控制台基础 使用file类永久性删除一个文件
- C++类详解
- 初识c++的类
- xml解析
- Install Adobe Flash plugin in Ubuntu 14.04
- C++的深拷贝与浅拷贝
- 站岗问题
- OC-debug调试&界面切换&多界面正反向传值
- 有关剃度下降和随机剃度下降的思考
- Android官方培训课程学习(三): 使用Fragment建立动态UI