一. C++空类的字节数
C++标准规定类的大小不为0,空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1。 如果在类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针指向虚函数表VTable,在32位机器上,一个对象会增加4个字节来存储此指针,它是实现面向对象中多态的关键。而虚函数本身和其他成员函数一样,是不占用对象的空间的。 我们来看下面一个例子:
class A{};
class b{
char ch;
void func(){}
};
class C{
char ch1; //占用1字节
char ch2; //占用1字节
virtual void func(){}
};
class D{
int n;
virtual void func(){}
};
则sizeof(A())=1 (空类大小为1),sizeof(B())=1 (包含一个char类型的非静态成员变量,普通成员函数不占用内存), sizeof(C()) = 8 (对象c实际上只有6字节有用数据,但是按照上面第二点编译器优化,编译器将此扩展为两个字,即8字节)
综上所述:一个类中,虚函数,成员函数(包括静态和非静态)和静态数据成员都不占用类的存储空间。对象大小= vptr(指向虚函数的指针,可能不止一个,这个很难确定,不过试过,类中定义了一个virtual函数,仍然为占用4个字节) + 所有非静态数据成员大小 + Aligin字节大小(依赖于不同的编译器)
二. C++空类默认产生哪些成员函数
一共有六个,分别是
class A{
public:
A(){}; //默认构造函数
A(const A&){}; //默认拷贝构造函数
~A(){}; //析构函数
A& operator=(const A&){}; //赋值运算符重载函数
A* operator&(); //取址运算符
const A* operator& () const; // 取址运算符const
};
三. C++ const的用法
转载这篇博客。
四. 为什么C++支持函数重载,而C语言不支持
- 函数重载
所谓的函数重载就是在一组同一个作用域类,一组函数的函数名相同,参数列表不同(类型不同/个数不同),返回值可同可不同。 - 实例分析
比如声明一个函数 void func(int x, int y),在C语言中,编译器进行编译之后,在库中的名字为_func;在C++中,编译器进行编译后名字为_func_int_int。
再来看另一个函数的声明void function(float x,float y),在C语言中,编译器进行编译之后,在库中的名字为_func;在C++中,编译器进行编译后名字为_func_float_float。
所以,编译器在链接阶段,都是找到相应的函数名,进行链接。在C语言中,两个函数的名字一样,就会在链接时报错。在C++中,两个函数饿名字不相同,就不会报错。 - 结论
C语言,在编译之后的函数标识是函数本身,就会存在两个同名函数。C++,在编译之后的函数标识是函数名+参数(c++有函数名修饰规则,函数名+类型一起决定)
五. C++ static的用法
- static修饰全局变量
(1)当同时编译多个文件时,所有未加static的全局变量和函数具有全局可见性,其它文件也可以访问;
(2)未加static的全局变量,在符号表中是global符号,要参与符号解析;加了static之后,是local符号,其他目标文件不可见,只在当前文件中可见,不参与符号解析过程。所以多个源文件可以定义同名的static全局变量,不会产生重定义错误。 - static修饰局部变量
修饰局部变量时,使它放在.data 或者.bss段(静态区),默认初始化为0,初始化不为0放在.data段,没有初始化或初始化为0放在.bss段。其生命周期是整个程序的声明周期。
- static修饰普通函数
修饰普通函数时,和修饰全局变量一样。函数经过编译产生一个函数符号,被static修饰后,就变为local符号,不参与符号解析,只在本文件中可见。 - static修饰类的成员变量
修饰类的成员变量时,就变成静态成员变量,不属于对象,属于类。不能在类的内部初始化,类中只能声明,定义需要在类外。类外定义时,不需要加static关键字,需要加类名作用域。 - static修饰类的成员函数
修饰类的成员函数时,变成静态成员函数,不属于对象,属于类。形参不会生成this指针,仅能访问类的静态数据和静态成员函数。调用不依赖对象,所以不能作为虚函数。用类名作用域调用。
五. 其它问题
参考链接。
六. 进程与线程
参考链接。
七. 内联函数
参考链接。
八. 左值引用与右值引用
当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。左值有持久的状态,而右值要么是字面常量,要么是在表达式求值过程中创建的对象,即左值持久,右值短暂。参考链接。