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