C++对象模型和this指针

C++对象模型和this指针

  • 成员变量和成员函数分开存储
  • this指针概念
  • 空指针访问成员函数
  • const修饰成员函数

成员变量和成员函数分开存储

在C++中,类内的成员变量和成员函数分开存储

只有非静态成员变量才属于类的对象上

我们首先看一下一个空对象:

#include
#include
using namespace std;
class Person
{

};

void test()
{
 Person p;
 cout << "size of Person_p = " << sizeof(p) << endl;
 
}
int main()
{
 test();
 return 0;
}

最后我们得出的结果为size of Person_p = 1

也就是说一个空对象他的所占内存为1

C++为什么这样子设计呢?

是因为编译器自动分配给空对象一个字节就能够区分不同的对象,防止弄混

每个空对象都有独一无二的地址

class Person
{
 int a;
};

void test()
{
 Person p;
 cout << "size of Person_p = " << sizeof(p) << endl;
 
}
int main()
{
 test();
 return 0;
}

此时的结果为size of Person_p = 4

为什么为4呢,是因为在其中有了int变量,变量所在的字节代替了空类的字节位置

经过测试我们获得:

int a;
static int b;
void func();
static funb();

只有int a非静态成员变量占对象空间,其余的静态成员变量,函数等均不占用对象空间

this指针概念

我们知道在C++中成员变量和成员函数是分开存储的

每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码

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

C++通过提供特殊的对象指针,this指针,解决上述问题。

this指针指向被调用的成员函数所属的对象

  • this指针是隐含每一个非静态成员函数内的一种指针
  • this指针不需要定义,直接使用即可

this指针的用途:

  • 当形参和成员变量同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this
class Person
{
public: 
 Person(int age)
 {
  age = age;
 }

 int age;
};

int main()
{
 Person p(10);

 cout << "Perosn_age = " << p.age;
}

此时会出现乱码,是因为在构造函数中变量混乱,ageage不分
我们要解决这个问题,有两种方式:
1、使用m_age,对成员变量进行命名,m为member,成员的含义

class Person
{
public: 
 Person(int age)
 {
  m_age = age;
 }

 int m_age;
};

2、使用this指针,对age变量进行指向


class Person
{
public: 
 Person(int age)
 {
  this->age = age;
 }

 int age;
};

这样子就能够正常的输出相应的数据,解决当形参和成员变量同名时的问题

并且此处的this所指向的是主函数的p

与上文对应:C++通过提供特殊的对象指针,this指针,解决上述问题。

this指针指向被调用的成员函数所属的对象

class Person
{
public: 
 Person(int age)
 {
  this->age = age;
 }

 Person& age_add(Person &p)
 {
  this->age += p.age;

  return *this;
 }
 int age;
};

int main()
{
 Person p(10);
 Person p2(20);

 p2.age_add(p).age_add(p).age_add(p);
 //链式编程思想
 cout << "Perosn2_age = " << p2.age << endl;
}

这里为this指针的第二用法,我们构造这个add函数,想让person类的age变量进行相加

就使用this指针,谁调用了这个函数,

谁就通过this指针将自身的age变量放入add函数中去进行计算输出,

同时我们又希望返回的是这个对象本身,方便我们后续的计算,

那么我们就可以用*this这个语法,返回对象本身

为什么要用*this呢,是因为this指向调用对象,而 *this是对this指针的追踪

其实就是 (*this) 等价于 (变量本身)

其中我们要注意的是:Person& age_add(Person &p)

不能够能改成:Person age_add(Person &p)

如果改成这种形式,我们返回的是一个值,而不是对象的地址了

就会调用拷贝构造函数,从而形成与p相同但是其实不是p的复制体

空指针访问成员函数

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针

如果用到this指针,需要加以判断保证代码的健壮性

示例:

class Person
{
 int m_age;
public:
 void showPerson_age()
 {
  cout << "Person_age = " << m_age << endl;
 }
 void showClass_name()
 {
  cout << "Class name is Person!" << endl;
 }
};
int main()
{
 Person* p1 = NULL;
 p1->showClass_name();
 p1->showPerson_age();
}

这个时候运行会报错,这是因为在语句:

cout << "Person_age = " << m_age << endl;中,
其实语句会自动被编译器变成
cout << "Person_age = " << this->m_age << endl;

这样无论什么对象调用此函数的时候显示的都是自己的age

但是因为我们定义的是一个空指针,所以空指针无age变量,编译器自然会报错

为了避免这种情况我们可以使用如下操作:

void showPerson_age()
{
 if(this==NULL)
 {
  return;
 }
 cout << "Person_age = " << m_age << endl;
}

这样就能够避免空指针的传入

const修饰成员函数

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数(是因为除了常函数其他函数可以修改变量值,就不符合常对象的定义了)

示例:

class Person {
public:
 Person() {
  m_A = 0;
  m_B = 0;
 }

 //this指针的本质是一个指针常量,指针的指向不可修改
 //如果想让指针指向的值也不可以修改,需要声明常函数
  //const Type* const pointer;
  //this = NULL; //不能修改指针的指向 Person* const this;
  //this->mA = 100; //但是this指针指向的对象的数据是可以修改的
  //const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
  void ShowPerson() const 
 {
  this->m_B = 100;
 }
 void MyFunc() const 
 {
  //mA = 10000;
 }

public:
 int m_A;
 mutable int m_B; //可修改 可变的
};


//const修饰对象  常对象
void test01() {

 const Person person; //常量对象  
 cout << person.m_A << endl;
 //person.mA = 100; //常对象不能修改成员变量的值,但是可以访问
 person.m_B = 100; //但是常对象可以修改mutable修饰成员变量

}

你可能感兴趣的:(C语言,c++,开发语言)