1.回归本质
class是一种特殊的struct:
在内存中class依旧可以看做变量的集合
class与struct遵循相同的内存对齐规则
class中的成员函数与成员变量是分开存放的
每个对象由独立的成员变量
所有对象共享类中的成员函数
对象内存布局示例:
#include <iostream>
#include <string>
using namespace std;
class A
{
int i;
int j;
char c;
double d;
public:
void print()
{
cout << "i = " << i << ","
<< "j = " << j << ","
<< "c = " << c << ","
<< "d = " << d << endl;
}
};
struct B
{
int i;
int j;
char c;
double d;
};
int main()
{
A a;
cout << "sizeof(A) = " << sizeof(A) << endl;//4+4+4+8 20bytes
cout << "sizeof(a) = " << sizeof(a) << endl;
cout << "sizeof(B) = " << sizeof(B) << endl;//4+4+4+8 20bytes
a.print();
B* p = reinterpret_cast<B*>(&a);
p->i = 100;
p->j = 200;
p->c = 'C';
p->d = 3.14;
a.print();
return 0;
}
运行结果
sizeof(A) = 20 //C++对象中不包含成员函数
sizeof(a) = 20
sizeof(B) = 20
i = 4197456,j = 0,c = ,d = 6.95323e-310
i = 100,j = 200,c = C,d = 3.14
- 类中的成员变量:
运行时的对象退化为结构体的形式:
所有成员变量在内存中依次排布
成员变量间可能存在内存间隙
可以通过内存地址直接访问成员变量
访问权限关键字在运行时失效 - 类中的成员函数:
类中的成员函数位于代码段中
调用成员函数时对象地址作为参数隐式传递
成员函数通过对象地址访问成员变量
C++语法规则隐藏了对象地址的传递过程
#include <iostream>
#include <string>
using namespace std;
class Demo
{
int mi;
int mj;
public:
Demo(int i, int j)
{
mi = i;
mj = j;
}
int getI()
{
return mi;
}
int getJ()
{
return mj;
}
int add(int value)
{
return mi + mj + value;
}
};
int main()
{
Demo d(1, 2);
cout << "sizeof(d) = " << sizeof(d) << endl; //8 bytes
cout << "d.getI() = " << d.getI() << endl; //1
cout << "d.getJ() = " << d.getJ() << endl; //2
cout << "d.add(3) = " << d.add(3) << endl; //6
return 0;
}
可以使用C语言的方式来改写
小结:
C++中的类对象在内存布局上与结构体相同
成员变量和成员函数在内存中分开存放
访问权限关键字在运行时失效
调用成员函数时对象地址作为参数隐式传递
2.继承对象模型
在C++编译器内部类可以理解为结构体
子类是由父类成员叠加子类新成员得到的
drived :Demo --> int mi,int mj, int mk;
Demo --> int mi,int mj;
继承对象模型示例:
#include <iostream>
#include <string>
using namespace std;
class Demo
{
protected:
int mi;
int mj;
};
class Derived : public Demo
{
int mk;
public:
Derived(int i, int j, int k)
{
mi = i;
mj = j;
mk = k;
}
void print()
{
cout << "mi = " << mi << ","
<< "mj = " << mj << ","
<< "mk = " << mk << endl;
}
};
struct Test
{
int mi;
int mj;
int mk;
};
int main()
{
cout << "sizeof(Demo) = " << sizeof(Demo) << endl; //8
cout << "sizeof(Derived) = " << sizeof(Derived) << endl; //12
Derived d(1,2,3);
Test* p = reinterpret_cast<Test*>(&d);
cout << "Before changing..." << endl;
d.print();
p->mi = 10;
p->mj = 20;
p->mk = 30;
cout << "After changing..." << endl;
d.print();
return 0;
}
运行结果
sizeof(Demo) = 8
sizeof(Derived) = 12
Before changing...
mi = 1,mj = 2,mk = 3
After changing...
mi = 10,mj = 20,mk = 30
3.多态对象模型
C++多态的实现原理:
- 当类中声明虚函数时,编译器会在类中生成一个虚函数表
- 虚函数表是一个存储成员函数地址的数据结构
- 虚函数表是由编译器自动生成与维护的
- virtual成员函数会被编译器放入虚函数表中
- 存在虚函数时,每个对象中都有一个指向虚函数表的指针
调用效率对比: 虚函数 < 普通成员函数
多态本质分析示例:
#include <iostream>
#include <string>
using namespace std;
class Demo
{
protected:
int mi;
int mj;
public:
virtual void print() //声明为虚函数
{
cout << "mi = " << mi << ","
<< "mj = " << mj << endl;
}
};
class Derived : public Demo
{
int mk;
public:
Derived(int i, int j, int k)
{
mi = i;
mj = j;
mk = k;
}
void print()
{
cout << "mi = " << mi << ","
<< "mj = " << mj << ","
<< "mk = " << mk << endl;
}
};
struct Test
{
void* p; //指向虚函数表的指针放在最开始的四个字节处
int mi;
int mj;
int mk;
};
int main()
{
cout << "sizeof(Demo) = " << sizeof(Demo) << endl;
cout << "sizeof(Derived) = " << sizeof(Derived) << endl;
Derived d(1,2,3);
Test* p = reinterpret_cast<Test*>(&d);
cout << "Before changing..." << endl;
d.print();
p->mi = 10;
p->mj = 20;
p->mk = 30;
cout << "After changing..." << endl;
d.print();
return 0;
}
运行结果
sizeof(Demo) = 12 //多出来的4个字节是虚函数指针成员变量
sizeof(Derived) = 16
Before changing...
mi = 1,mj = 2,mk = 3
After changing...
mi = 10,mj = 20,mk = 30
可以使用C语言来实现C++多态
小结
继承的本质就是父子间成员变量的叠加
C++中的多态是通过虚函数表实现的
虚函数表是由编译器自动生成与维护的
虚函数的调用效率低于普通成员函数