空类
默认添加哪些函数
1) Empty(); // 缺省构造函数//
2) Empty( const Empty& ); // 拷贝构造函数//
3) ~Empty(); // 析构函数//
4) Empty& operator=( const Empty& ); // 赋值运算符//
空类大小
- C++空类大小不为0,不同编译器设置不一样,VS设置为1
- C++标准指出不允许一个对象大小为0,不同对象不能有相同地址
- 带有虚函数的C++类大小不为1,因为每一个对象会有一个vptr指向虚函数表,具体大小根据指针大小确定。
- 编译器自动为空类分配一个字节大小,这样就可以保证每个实例均有独一无二的内存地址
- 当空类作为基类的时候,大小就优化为0了,子类大小就是子类本身大小,这就是空白基类最优化
空类大小为1字节
class A {};
int main(){
cout<<sizeof(A)<<endl;// 输出 1;
A a;
cout<<sizeof(a)<<endl;// 输出 1;
return 0;
}
虚函数类对象有一个虚表指针_vptr
class A { virtual void Fun(){} };
int main(){
cout<<sizeof(A)<<endl;// 输出 4(32位机器)/8(64位机器);
A a;
cout<<sizeof(a)<<endl;// 输出 4(32位机器)/8(64位机器);
return 0;
}
静态成员放在静态存储区,不占用类大小,普通函数也是
class A { static int a; };
int main(){
cout<<sizeof(A)<<endl;// 输出 1;
A a;
cout<<sizeof(a)<<endl;// 输出 1;
return 0;
}
如何设计一个计算仅单个子类的对象个数
- 添加一个static变量count作为计数器
- 类定义结束之后初始化count
- 构造函数中对count+1
- 设计拷贝构造函数,count+1
- 设计赋值构造函数,count+1
- 析构函数中count–
友元
什么是友元
友元用于在类之间共享私有成员,一个类将另一个类声明为友元,这样就可以让友元类访问私有成员。友元可以是一个函数、一个类或者一个成员函数(一个类将另一个类的成员函数声明为其友元)。
class MyClass {
private:
int private_member;
friend void FriendFunction(MyClass& myclass);
};
void FriendFunction(MyClass& myclass) {
myclass.private_member = 42; // 可以访问 MyClass 的私有成员
}
为什么友元必须在类内部声明
否则编译器无法识别它是友元函数。
使用友元时应该注意
- 友元关系不能被继承
- 友元关系是单向的,不具有交换性。
- 不具有传递性。
类的对象存储空间
- 非静态成员的数据类型大小之和
- 编译加入的额外成员变量(比如指向虚函数表的指针)
- 内存对齐另外分配的空间大小,类内的数据也是需要进行内存对齐操作的
- 当该类是某类的派生类,那么派生类继承的基类部分的数据成员也会存放在派生类空间中,也会对派生类进行扩展
类的数据成员和成员函数内存分布
代码来源阿秀的学习笔记
#include <iostream>
using namespace std;
class Person
{
public:
Person()
{
this->age = 23;
}
void printAge()
{
cout << this->age <<endl;
}
~Person(){}
public:
int age;
};
int main()
{
Person p;
cout << "对象地址:"<< &p <<endl;
cout << "age地址:"<< &(p.age) <<endl;
cout << "对象大小:"<< sizeof(p) <<endl;
cout << "age大小:"<< sizeof(p.age) <<endl;
return 0;
}
//输出结果
//对象地址:0x7fffec0f15a8
//age地址:0x7fffec0f15a8
//对象大小:4
//age大小:4
- 成员函数不占用对象内存,因为被放在代码区
- 静态函数也是放在代码区的,静态成员函数与一般成员函数唯一区别就是没有this指针,因此不能访问非静态数据成员。