Aoki Job Seeker

C++对象模型初探

2019-03-23
C++

C++对象模型初探



1.成员变量和函数的存储

在C语言中,分开来声明,也就说,语言本身并没有支持“数据”和“函数”之间的关联性,我们把这种程序方法称为“程序性的”,由一组“分布在各个以功能为导向的函数中的算法驱动,它们处理的是共同的外部数据。
C++实现了“封装”,那么数据(成员属性)和操作(成员函数)是什么样的呢?
“数据”和“处理数据的操作(函数)”是分开存储的。

  • C++中的非静态数据成员直接内含在类对象中,就像C struct一样
  • 成员函数(member function)虽然内含正在class声明之内,却不出现在对象中
  • 每一个非内联成员函数只会的诞生一份函数实例
#include <iostream>
using namespace std;

class Myclass
{
public:
	int m_A;
};

class Myclass1
{
public:
	int m_A;
	static int m_B;
};

class Myclass2
{
public:
	void test01()
	{
		cout << "001" << endl;
	}
public:
	static int m_A;
};

class Myclass3
{
public:
	static void test02()
	{
		cout << "002" << endl;
	}

public:
	int m_A;
	static int m_B;
};

class Myclass4
{
public:
	void test03()
	{
		cout << "003" << endl;
	}
	static void test04()
	{
		cout << "004" << endl;
	}
public:
	int m_A;
	static int m_B;
};


int main()
{
	Myclass myclass;
	Myclass1 myclass1;
	Myclass2 myclass2;
	Myclass3 myclass3;
	Myclass4 myclass4;
	cout << "size of myclass:" << sizeof(myclass) << endl;
	cout << "size of myclass1:" << sizeof(myclass1) << endl;
	cout << "size of myclass2:" << sizeof(myclass2) << endl;
	cout << "size of myclass3:" << sizeof(myclass3) << endl;
	cout << "size of myclass4:" << sizeof(myclass4) << endl;
	return 0;
}

输出结果如下:

从输出结果我们可以看出,C++中成员变量和成员属性是分开存储的。 而且,只有非静态成员才属于对象身上。

2.this指针

通过上面的例子我们知道,C++的数据和操作时分开存储的,并且每个非内联成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码。
那么问题是,这块代码是如何区分是哪个对象调用自己的呢?
C++通过提供特殊的对象指针,this指针,来解决上述问题。this指针指向被调用的成员函数所属的对象。
C++规定,this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址。也就是说,虽然我们没有写上this指针,编译器在编译的时候也会加上的。因此,this指针也被称为“指向本对象的指针”,this指针不并不是对象的一部分,并不会影响sizeof(对象)对的结果。
this指针是C++实现封装的一种机制,它将对象和该对象调用的非成员函数连接在一起,在外部看来,每个对象都拥有自己的成员函数。一般情况下,并不写this,而是让系统进行默认设置。
this指针永远指向当前对象。 成员函数通过this指针即可知道操作的是哪个对象的数据。this指针是一种隐含指针,它隐含于每个类的非静态成员函数中,this指针无须定义,直接使用即可。
静态成员函数内部没有this指针,静态成员函数不能操作非静态成员变量。

3.this指针的使用

  • 当形参和成员变量同名时,可用this指针区分
  • 在类的非静态成员函数中返回对象本身,可用return *this
#include <iostream>
#include<string>
using namespace std;


class Person
{
public:
	Person(string name, int age)
	{//当形参与成员变量名相同时,可以使用this指针来区分
		this->age = age;
		this->name = name;
	}

	Person Person_Plus(Person &person)
	{
		string newname = this->name + person.name;
		int newage = this->age + person.age;
		Person newperson(newname, newage);
		return newperson;
	}

	void show()
	{
		cout << "Name:" << name << ",Age:" << age << endl;
	}

public:
	int age;
	string name;
};

void test()
{
	Person person("Aoki", 20);
	person.show();

	Person p1("Aoki", 20);
	Person p2("青木", 15);
	Person p3 = p1.Person_Plus(p2);
	p3.show();
}

int main()
{
	test();
}


输出结果如下:

4.const修饰成员函数(常函数)

  • 用const修饰成员函数时,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通变量
  • 当成员变量类型符前面用mutable修饰时例外
#include <iostream>
using namespace std;


class Person
{
public:
	Person()
	{
		this->m_A = 0;
		this->m_B = 0;
	}
	void  showinfor () const 
	{
		//this->m_B = 10;
		this->m_A=100;
		cout << "m_A=" <<m_A<< endl;
		cout << "m_B=" << m_B<<endl;
	}


	mutable int m_A;//如果需要使用常函数修改变量,加mutable关键字
	int m_B;
};

void test()
{
	Person p1;
	p1.showinfor();
}
int main()
{
	test();
}

当我们试图使用常函数对成员变量进行修改时,编译器会报错。报错结果如下图:

由此可知,常函数不能修改this指针指向的值。
那么,当我们需要使用常函数对成员变量进行修改时呢?那么,我们可以在变量前面加mutable关键字。输出结果如下:

5.const修饰对象(常对象)

  • 常对象只能调用const的成员函数
  • 常对象可访问const或非const数据成员,但是不能修改,除非成员用mutable修饰

#include <iostream>
using namespace std;


class Person
{
public:
	Person()
	{
		this->m_A = 0;
		this->m_B = 0;
	}
	void  showinfor () const 
	{
		//this->m_B = 10;
		this->m_A = 100;
		cout << "m_A=" <<m_A<< endl;
		cout << "m_B=" << m_B<<endl;
	}
	void show()
	{
		cout << "m_A=" << this->m_A << endl;
		cout << "m_B=" << this->m_B << endl;
	}


	mutable int m_A;//如果需要使用常函数修改变量,加mutable关键字
	int m_B;
};

void test()
{
	const Person p1;
	Person p2;
	p2.show();
	p2.showinfor();
	p1.showinfor();
	//p1.m_B = 100;
	p1.m_A = 20;
	//p1.show();
	cout << "m_A=" << p1.m_A << endl;
	cout << "m_B=" << p1.m_B << endl;
}
int main()
{
	test();
}

当我试图使用常对象来对成员变量进行修改时,编译器报错如下:

常对象不能修改没有关键字mutable修饰的成员变量,也就是说,如果一个变量被关键字mutable修改时,那么常对象可以对其进行修改。
当我试图使用常对象来访问普通成员函数时,编译器报错如下:

也就说,常对象不能调用普通成员函数,它只能调用常函数。
最终输出结果如下所示:

5.常函数与常对象的总结

  1. 常函数
    • 常函数格式:返回类型 函数名()const{}
    • 常函数不能修改this指针指向的值
    • 如果需要修改,就必须用关键字mutable来修饰成员变量
  2. 常对象
    • 常对象就是在对象前加上const修饰符,如 const Person p1
    • 常对象不可以调用普通成员函数
    • 常对象可以调用常函数
    • 常对象可以修改用mutable关键字修饰的成员变量







The End



Similar Posts

上一篇 静态成员

下一篇 友元

Comments