C++核心程式設計---4.3 類和對象-對象模型和 this 指針【P114~P117】
- 4.3 類和對象-對象模型和 this 指針
-
- 4.3.1 成員變量和成員函數分開存儲
- 4.3.2 this 指針的用途
- 4.3.3 空指針通路成員函數
- 4.3.4 const 修飾成員函數
4.3 類和對象-對象模型和 this 指針
4.3.1 成員變量和成員函數分開存儲
在C++中,類内的成員變量和成員函數分開存儲
隻有非靜态成員變量才屬于類的對象上
#include<iostream>
#include<string>
using namespace std;
//成員變量和成員函數是分開存儲的
class Person
{
int m_A;//非靜态成員變量,屬于類的對象上
static int m_B;//靜态成員變量(特點是要類内聲明,類外初始化),不屬于類的對象上
void func(){};//非靜态成員函數 不屬于類的對象上
static void func02() {};//非靜态成員函數 不屬于類的對象上
};
int Person::m_B = 0;//類外初始化
void test01()//主要了解空對象占多大記憶體
{
Person p;
//空對象占用記憶體空間為 1 位元組
//C++編譯器會給每個空對象也配置設定一個位元組空間,是為了區分空對象占記憶體的位置
//每個空對象也應該有一個獨一無二的記憶體位址
cout << "size of p = " << sizeof(p) << endl;
}
void test02()
{
Person p;
cout << "size of p = " << sizeof(p) << endl;
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
4.3.2 this 指針的用途
通過上一節内容知道C++中成員變量和成員函數是分開存儲的
每一個非靜态成員函數隻會誕生一份函數執行個體,也就是說多個同類型的對象會共用一塊代碼
那麼,這一塊代碼是如何區分是哪個對象調用自己的呢?
C++是通過提供特殊的對象指針,this 指針,解決上述問題:this 指針指向被調用的成員函數所屬的對象(哪個對象調用了這個共用的成員函數,this 指針就會指向誰)
this 指針是隐含在每一個非靜态成員函數内的一種指針
this 指針不需要定義,直接使用即可
this 指針的用途:
- 當形參和成員變量同名時,可用 this 指針來區分
- 在類的非靜态成員函數中傳回對象本身,可使用 return *this ( * :解引用操作,傳回這個對象 )
#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
Person(int age)//形參名稱
{
//this指針指向的是被調用的成員函數所屬的對象
this->age = age;
}
Person & PersonAddAge(Person &p)//如果去掉引用符号,就會傳回值,建立了新的對象;但如果加上引用符号,傳回的一直是本體
{
this->age += p.age;
//this 指向p2的指針,而*this指向的就是p2這個對象本體
return *this;
}
int age;//成員屬性
};
//1、解決形參和成員變量名稱沖突的問題
void test01()
{
Person p1(18);
cout << "p1的年齡為: " << p1.age << endl;
}
//2、傳回對象本身用*this
void test02()
{
Person p1(10);
Person p2(10);
//鍊式程式設計思想
p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
cout << "p2的年齡是: " << p2.age << endl;
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
4.3.3 空指針通路成員函數
C++中空指針也是可以調用成員函數的,但是也要注意有沒有用到this指針
如果用到 this 指針,需要加以判斷保證代碼的健壯性
#include<iostream>
#include<string>
using namespace std;
//空指針調用成員函數
class Person
{
public:
void showClassName()
{
cout << "this is Person class" << endl;
}
void showPersonAge()
{
if (this == NULL)
{
return;
}
//報錯原因是因為傳入的指針是NULL
cout << "age = " << this->m_Age << endl;
}
int m_Age;
};
void test01()
{
Person *p = NULL;
p->showClassName();
p->showPersonAge();//這一行報錯,因為空指針沒有指向實體對象,再調用這個不存在的對象的成員屬性就更荒謬了
}
int main()
{
test01();
system("pause");
return 0;
}
4.3.4 const 修飾成員函數
常函數
- 成員函數後加 const 後我們稱這個函數為常函數
- 常函數内不可以修改成員屬性
- 成員屬性聲明時加關鍵字 mutable 後,在常函數中依然可以修改
常對象
- 聲明對象前加 const 稱該對象為常對象
- 常對象隻能調用常函數
#include<iostream>
#include<string>
using namespace std;
//1、常函數
class Person
{
public:
//this 指針的本質 是指針常量 指針的指向是不可以修改的
//Person * const this; this 指針的指向不可以修改
//const Person * const this; 這時 this 指針指向的值也不可以修改了
void showPersonName()const //上邊一行注釋的等效做法,這時成員函數就是常函數了,常函數内就不可以再修改成員屬性的值了
{
//this->m_A = 100;
this->m_B = 100;
}
void func()
{
}
int m_A;
mutable int m_B;//特殊變量,即使在常函數中也可以修改這個值
};
void test01()
{
Person p;
p.showPersonName();
}
//2、常對象
void test02()
{
const Person p;//在對象前加 const ,變為常對象
p.m_A = 100;//報錯,常對象的值不可以修改
p.m_B = 100;
//常對象隻能調用常函數
p.showPersonName();//常對象調用常函數,沒毛病
p.func();//報錯,常對象調用的不是常函數
}
int main()
{
test01();
test02();
system("pause");
return 0;
}