C++——对象模型分析

1.class是一种特殊的struct:

(1)在内存中class依旧可以看作变量的集合

(2)class和struct遵循相同的对齐规则

(3)class中的成员函数与成员变量是分开存放的,每个对象有独立的成员变量,所有对象共享类中的成员函数

复制代码
#include <iostream>
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(B)" << sizeof(B) << endl; //sizeof(B)24
	
	//不管在class A中加不加成员函数,A的大小都不变
	cout << "sizeof(A)" << sizeof(A) << endl; //sizeof(A)24
	cout << "sizeof(a)" << sizeof(a) << endl; //sizeof(a)24
	a.print();
	B* p = reinterpret_cast<B*>(&a); //将a转成结构体
	p->i = 1;
	p->j = 2;
	p->c = 'c';
	p->d = 3;
	a.print();
	return 0;
}

运行结果:

sizeof(B)24

sizeof(A)24

sizeof(a)24

i=-858993460 j=-858993460 c=?d=-9.25596e+61

i=1 j=2 c=c d=3

原因:运行时的对象退化为结构体的形式

类中的权限仅在编译时有效,运行时将会失效

下面是C语言来模拟C++中的类,成员函数和成员变量分开存储,用typedef来模拟C++中的private

Complex.h

复制代码
#pragma once
//typedef void Demo 隐藏了 Demo 的实际结构体定义,外部代码无法直接访问 Demo 的成员,只能通过提供的函数操作(封装性)
typedef void Demo;
Demo* Demo_Create(int i, int j);
int Demo_GetI(Demo* pThis);
int Demo_GetJ(Demo* pThis);
int Demo_Add(Demo* pThis,int value);
void Demo_Free(Demo* pThis);

Complex.cpp

复制代码
#include "Complex.h"
#include "malloc.h"
struct ClassDemo
{
	int mi;
	int mj;
};
Demo* Demo_Create(int i, int j) {
	struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo));
	if (ret != NULL) {
		ret->mi = i;
		ret->mj = j;
	}
	return ret;
}
int Demo_GetI(Demo* pThis) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mi;
}
int Demo_GetJ(Demo* pThis) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mj;
}
int Demo_Add(Demo* pThis, int value) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mi + obj->mj + value;
}

void Demo_Free(Demo* pThis) {
	free(pThis);
}

main.cpp

复制代码
#include <iostream>
using namespace std;
#include"Complex.h"
int main() {
	Demo* d = Demo_Create(1, 2);
	printf("d.mi=%d\n", Demo_GetI(d)); //d.mi=1
	printf("d.mj=%d\n", Demo_GetJ(d)); //d.mi=2
	printf("Add(3)=%d\n", Demo_Add(d,3)); //Add(3)=6
	// d->mi = 100; 报错,mi是私有成员,在C语言中没有private关键字,所以要通过typedef对Demo类进行信息隐藏,用于模拟private,只展示可以调用的成员函数
	Demo_Free(d);
	return 0;
}

在C++编译器的内部类可以理解为结构体

子类是由父类成员叠加子类新成员得到的

复制代码
#include <iostream>
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; //sizeof(Demo)=8
	cout << "sizeof(Derived)=" << sizeof(Derived) << endl; //sizeof(Derived)=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();
}

运行结果:

sizeof(Demo)=8

sizeof(Derived)=12

Before changing...

mi=1,mj=2,mk=3

After changing...

mi=10,mj=20,mk=30

2.C++多态的实现原理

(1)当类中声明虚函数时,编译器会在类中生成一个虚函数表

(2)虚函数表是一个存储成员函数地址的数据结构

(3)虚函数表是由编译器自动生成与维护的

(4)virtual成员函数会被编译器放入虚函数表中

(5)存在虚函数时,每个对象中都有一个指向虚函数表的指针

虚函数调用效率小于普通函数的调用

加了virtual关键字后,类大小发生了变化

复制代码
#include <iostream>
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
{
	int mi;
	int mj;
	int mk;
};
int main() {
	cout << "sizeof(Demo)=" << sizeof(Demo) << endl; //sizeof(Demo)=16
	cout << "sizeof(Derived)=" << sizeof(Derived) << endl; //sizeof(Derived)=24
	
}

Demo 的大小 = vptr (8) + mi (4) + mj (4) = 16 字节,Derived 因继承 + 对齐最终 24 字节;

虚函数指针默认放在类对象内存的最起始位置

复制代码
#include <iostream>
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; //// 对应Derived对象中的虚函数表指针(vptr)
	int mi;
	int mj;
	int mk;
};
int main() {
	cout << "sizeof(Demo)=" << sizeof(Demo) << endl; //sizeof(Demo)=16
	cout << "sizeof(Derived)=" << sizeof(Derived) << endl; //sizeof(Derived)=24
	Derived d(1, 2, 3);
	Test* p = reinterpret_cast<Test*>(&d);
	d.print();
	return 0;
}

用C语言实现面向对象

Complex.h

复制代码
#pragma once
typedef void Demo;
typedef void Derived;

Demo* Demo_Create(int i, int j);
int Demo_GetI(Demo* pThis);
int Demo_GetJ(Demo* pThis);
int Demo_Add(Demo* pThis,int value);
void Demo_Free(Demo* pThis);

Derived* Derived_Create(int i, int j, int k);
int Derived_GetK(Derived* pThis);
int Derived_Add(Derived* pThis, int value);
void Derived_Free(Demo* pThis);

Complex.cpp

复制代码
#include "Complex.h"
#include "malloc.h"
struct ClassDemo
{
	int mi;
	int mj;
};
struct ClassDerived
{
	struct ClassDemo d;
	int mk;
};
Demo* Demo_Create(int i, int j) {
	struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo));
	if (ret != NULL) {
		ret->mi = i;
		ret->mj = j;
	}
	return ret;
}
int Demo_GetI(Demo* pThis) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mi;
}
int Demo_GetJ(Demo* pThis) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mj;
}
int Demo_Add(Demo* pThis, int value) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mi + obj->mj + value;
}

void Demo_Free(Demo* pThis) {
	free(pThis);
}

Derived* Derived_Create(int i, int j, int k) {
	struct ClassDerived* ret = (struct ClassDerived*)malloc(sizeof(struct ClassDerived));
	if (ret != NULL) {
		ret->d.mi = i;
		ret->d.mj = j;
		ret->mk = k;
	}
	return ret;
}
int Derived_GetK(Derived* pThis) {
	struct ClassDerived* obj = (struct ClassDerived*)pThis;
	return obj->mk;
}
int Derived_Add(Derived* pThis, int value) {
	struct ClassDerived* obj = (struct ClassDerived*)pThis;
	return obj->d.mi + obj->d.mj + obj->mk + value;
}
void Derived_Free(Demo* pThis) {
	free(pThis);
}

main.cpp

复制代码
#include <iostream>
using namespace std;
#include "Complex.h"
void run(Demo* p, int v) {
	int r = Demo_Add(p, 3);
	printf("r=%d\n", r);
}
int main() {
	Demo* pb = Demo_Create(1, 2);
	Derived* pd = Derived_Create(1, 22, 333);
	printf("pb->add(3)=%d\n", Demo_Add(pb, 3)); //pb->add(3)=6
	printf("pd->add(3)=%d\n", Derived_Add(pd, 3)); //pd->add(3)=359
	run(pb, 3); //r=6
	run(pd, 3); //r=26,原因是没有实现多态,仍然是1+22+3
	Demo_Free(pb);
	Derived_Free(pd);
	return 0;
}

下面将实现多态:

Complex.h

复制代码
#pragma once
typedef void Demo;
typedef void Derived;

Demo* Demo_Create(int i, int j);
int Demo_GetI(Demo* pThis);
int Demo_GetJ(Demo* pThis);
int Demo_Add(Demo* pThis,int value);
void Demo_Free(Demo* pThis);

Derived* Derived_Create(int i, int j, int k);
int Derived_GetK(Derived* pThis);
int Derived_Add(Derived* pThis, int value);
void Derived_Free(Demo* pThis);

Complex.cpp

复制代码
#include "Complex.h"
#include "malloc.h"

static int Demo_Virtual_Add(Demo* pThis, int value);
static int Derived_Virtual_Add(Demo* pThis, int value);
//虚函数表的结构体
struct VTable
{
	int(*pAdd)(Derived*, int); //指向成员函数的指针
};
struct ClassDemo
{
	struct VTable* vtbl; //指针用于指向虚函数表
	int mi;
	int mj;
};
struct ClassDerived
{
	struct ClassDemo d;
	int mk;
};

static struct VTable g_Demo_vtbl =//通过static关键字将虚函数表隐藏,外部不可访问
{
	Demo_Virtual_Add
};
static struct VTable g_Derived_vtbl =//通过static关键字将虚函数表隐藏,外部不可访问
{
	Derived_Virtual_Add
};
Demo* Demo_Create(int i, int j) {
	struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo));
	if (ret != NULL) {
		ret->vtbl = &g_Demo_vtbl;//关联具体对象和虚函数表
		ret->mi = i;
		ret->mj = j;
	}
	return ret;
}
int Demo_GetI(Demo* pThis) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mi;
}
int Demo_GetJ(Demo* pThis) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mj;
}
//定义虚函数表中指针所指向的具体函数
static int Demo_Virtual_Add(Demo* pThis, int value) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->mi + obj->mj + value;
}

static int Derived_Virtual_Add(Demo* pThis, int value) {
	struct ClassDerived* obj = (struct ClassDerived*)pThis;
	return obj->d.mi + obj->d.mj + obj->mk + value;
}

//具体的虚函数
int Demo_Add(Demo* pThis, int value) {
	struct ClassDemo* obj = (struct ClassDemo*)pThis;
	return obj->vtbl->pAdd(pThis, value);
}

void Demo_Free(Demo* pThis) {
	free(pThis);
}

Derived* Derived_Create(int i, int j, int k) {
	struct ClassDerived* ret = (struct ClassDerived*)malloc(sizeof(struct ClassDerived));
	if (ret != NULL) {
		ret->d.vtbl = &g_Derived_vtbl;
		ret->d.mi = i;
		ret->d.mj = j;
		ret->mk = k;
	}
	return ret;
}
int Derived_GetK(Derived* pThis) {
	struct ClassDerived* obj = (struct ClassDerived*)pThis;
	return obj->mk;
}
int Derived_Add(Derived* pThis, int value) {
	struct ClassDerived* obj = (struct ClassDerived*)pThis;
	return obj->d.vtbl->pAdd(pThis, value);
}
void Derived_Free(Demo* pThis) {
	free(pThis);
}

main.cpp

复制代码
#include <iostream>
using namespace std;
#include "Complex.h"
void run(Demo* p, int v) {
	int r = Demo_Add(p, 3);
	printf("r=%d\n", r);
}
int main() {
	Demo* pb = Demo_Create(1, 2);
	Derived* pd = Derived_Create(1, 22, 333);
	printf("pb->add(3)=%d\n", Demo_Add(pb, 3)); //pb->add(3)=6
	printf("pd->add(3)=%d\n", Derived_Add(pd, 3)); //pd->add(3)=359
	run(pb, 3); //r=6
	run(pd, 3); //r=26,原因是没有实现多态,仍然是1+22+3
	Demo_Free(pb);
	Derived_Free(pd);
	return 0;
}
相关推荐
云泽8082 小时前
C++ STL set 容器全解析:从基础用法、算法实践到云同步实战
开发语言·c++·算法
山上三树2 小时前
C++ 智能指针详解与代码示例
开发语言·c++
小杍随笔2 小时前
【Rust模块化进阶:深入解析mod.rs的用法与现代实践(1.94版本)】
开发语言·后端·rust
小鹿软件办公2 小时前
KDE 重磅发布:digiKam 9.0 正式登场,全面升级 Qt 6 核心
开发语言·qt·digikam
Ronin2 小时前
QT中使用toInt函数判断条件时,要注意越界
开发语言·qt
载数而行5202 小时前
QT系列,对象树 栈和堆 QDebug以及日志打印
c++·qt·学习
小二·2 小时前
Go 语言系统编程与云原生开发实战(第35篇)
开发语言·云原生·golang
xiaoye-duck2 小时前
《算法题讲解指南:优选算法-分治-快排》--45.数组中的第k个最大元素,46.最小的k个数
c++·算法
SCBAiotAigc2 小时前
2026.3.7:具身智能之51单片机<二>:ISP烧录过程
c++·人工智能·单片机·嵌入式硬件·51单片机·c