C++面向对象模型初探


C++对象模型可以概括为以下2部分:

  1. 语言中直接支持面向对象程序设计的部分,主要涉及如构造函数、析构函数、虚函数、继承(单继承、多继承、虚继承)、多态等等。
  2. 对于各种支持的底层实现机制。
    在这里插入图片描述

C++中的class从面向对象理论出发,将变量(属性)和函数(方法)集中定义在一起,用于描述现实世界中的类。

从计算机的角度,程序依然由数据段和代码段构成。

C++编译器如何完成面向对象理论到计算机程序的转化?

换句话:C++编译器是如何管理类、对象、类和对象之间的关系

class MyClass01{
public:
	int mA;
};

class MyClass02{
public:
	int mA;
	static int sB;
};

class MyClass03{
public:
	void printMyClass(){
		cout << "hello world!" << endl;
	}
public:
	int mA;
	static int sB;
};

class MyClass04{
public:
	void printMyClass(){
		cout << "hello world!" << endl;
	}
	static void ShowMyClass(){
		cout << "hello world!" << endl;
	}
public:
	int mA;
	static int sB;
};

int main(){

	MyClass01 mclass01;
	MyClass02 mclass02;
	MyClass03 mclass03;
	MyClass04 mclass04;

	cout << "MyClass01:" << sizeof(mclass01) << endl; //4
	//静态数据成员并不保存在类对象中
	cout << "MyClass02:" << sizeof(mclass02) << endl; //4
	//非静态成员函数不保存在类对象中
	cout << "MyClass03:" << sizeof(mclass03) << endl; //4
	//静态成员函数也不保存在类对象中
	cout << "MyClass04:" << sizeof(mclass04) << endl; //4

	return EXIT_SUCCESS;
}

通过上面的案例,我们可以的得出:C++类对象中的变量和函数是分开存储。

编译器对属性和方法的处理机制

C++类对象中的成员变量和成员函数是分开存储的

成员变量:

  1. 普通成员变量: 存储于对象中,与struct变量有相同的内存布局和字节对齐方式
  2. 静态成员变量: 存储于全局数据区中

成员函数: 存储于代码段中。

问题出来了:很多对象共用一块代码?代码是如何区分具体对象的那?
换句话说:int getK() const { return k; },代码是如何区分,具体obj1、obj2、obj3对象的k值?

那就要说到C++编译器的另一个处理方法了

C++编译器对普通成员函数的内部处理

在这里插入图片描述
编译器处理成员函数时会自己带一个this指针,用于指向当前类的数据。

总结

  1. C++类对象中的成员变量和成员函数是分开存储的。C语言中的内存四区模型仍然有效!
  2. C++中类的普通成员函数都隐式包含一个指向当前对象的this指针。
  3. 静态成员函数与普通成员函数的区别:
    静态成员函数不包含指向具体对象的指针
    普通成员函数包含一个指向具体对象的指针

this指针

在这里插入图片描述

this指针工作原理

通过上例我们知道,c++的数据和操作也是分开存储,并且每一个非内联成员函数(non-inline member function)只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码

那么问题是:这一块代码是如何区分那个对象调用自己的呢?

在这里插入图片描述
c++通过提供特殊的对象指针,this指针,解决上述问题。This指针指向被调用的成员函数所属的对象。

c++规定,this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址,也就是说虽然我们没有写上this指针,编译器在编译的时候也是会加上的。

因此this也称为“指向本对象的指针”,this指针并不是对象的一部分,不会影响sizeof(对象)的结果。

this指针永远指向当前对象。

注意: 静态成员函数内部没有this指针,静态成员函数不能操作非静态成员变量。

this指针的使用

  1. 当形参和成员变量同名时,可用this指针来区分
  2. 在类的非静态成员函数中返回对象本身,可使用return *this。
class Person{
public:
	//1. 当形参名和成员变量名一样时,this指针可用来区分
	Person(string name,int age){
		//name = name;
		//age = age; //输出错误
		this->name = name;
		this->age = age;
	}
	//2. 返回对象本身的引用
	//重载赋值操作符
	//其实也是两个参数,其中隐藏了一个this指针
	Person PersonPlusPerson(Person& person){
		string newname = this->name + person.name;
		int newage = this->age + person.age;
		Person newperson(newname, newage);
		return newperson;
	}
	void ShowPerson(){
		cout << "Name:" << name << " Age:" << age << endl;
	}
public:
	string name;
	int age;
};

//3. 成员函数和全局函数(Perosn对象相加)
Person PersonPlusPerson(Person& p1,Person& p2){
	string newname = p1.name + p2.name;
	int newage = p1.age + p2.age;
	Person newperson(newname,newage);
	return newperson;
}

int main(){

	Person person("John",100);
	person.ShowPerson();

	cout << "---------" << endl;
	Person person1("John",20);
	Person person2("001", 10);
	//1.全局函数实现两个对象相加
	Person person3 = PersonPlusPerson(person1, person2);
	person1.ShowPerson();
	person2.ShowPerson();
	person3.ShowPerson();
	//2. 成员函数实现两个对象相加
	Person person4 = person1.PersonPlusPerson(person2);
	person4.ShowPerson();

	system("pause");
	return EXIT_SUCCESS;
}

全局函数PK成员函数

  1. 把全局函数转化成成员函数,通过this指针隐藏左操作数
Test add(Test &t1, Test &t2)===》Test add(Test &t2)
  1. 把成员函数转换成全局函数,多了一个参数
void printAB()===void printAB(Test *pthis)
  1. 函数返回元素和返回引用
Test& add(Test &t2) //*this //函数返回引用
	{
		this->a = this->a + t2.getA();
		this->b = this->b + t2.getB();
		return *this; //*操作让this指针回到元素状态
	} 

Test add2(Test &t2) //*this //函数返回元素
	{
		//t3是局部变量
		Test t3(this->a+t2.getA(), this->b + t2.getB()) ;
		return t3;
	}

const修饰成员函数

  1. 用const修饰的成员函数时,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量,
  2. 当成员变量类型符前用mutable修饰时例外。
//const修饰成员函数
class Person{
public:
	Person(){
		this->mAge = 0;
		this->mID = 0;
	}
	//在函数括号后面加上const,修饰成员变量不可修改,除了mutable变量
	void sonmeOperate() const{
		//this->mAge = 200; //mAge不可修改
		this->mID = 10; //const Person* const tihs;
	}
	void ShowPerson(){
		cout << "ID:" << mID << " mAge:" << mAge << endl;
	}
private:
	int mAge;
	mutable int mID;
};

int main(){

	Person person;
	person.sonmeOperate();
	person.ShowPerson();

	system("pause");
	return EXIT_SUCCESS;
}

const修饰对象(常对象)

  1. 常对象只能调用const的成员函数
  2. 常对象可访问 const 或非 const 数据成员,不能修改,除非成员用mutable修饰
class Person{
public:
	Person(){
		this->mAge = 0;
		this->mID = 0;
	}
	void ChangePerson() const{
		mAge = 100;
		mID = 100;
	}
	void ShowPerson(){
		cout << "ID:" << this->mID << " Age:" << this->mAge << endl;
	}

public:
	int mAge;
	mutable int mID;
};

void test(){	
	const Person person;
	//1. 可访问数据成员
	cout << "Age:" << person.mAge << endl;
	//person.mAge = 300; //不可修改
	person.mID = 1001; //但是可以修改mutable修饰的成员变量
	//2. 只能访问const修饰的函数
	//person.ShowPerson();
	person.ChangePerson();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值