1. C++對象模型和this指針
1.1 成員變量和成員函數分開存儲
在C++中,類內的成員變量和成員函數分開存儲
只有非靜態成員變量才屬於類的對象上
class Person {
public:
Person() {
mA = 0;
}
//非靜態成員變量佔對象空間
int mA;
//靜態成員變量不佔對象空間
static int mB;
//函數也不佔對象空間,所有函數共享一個函數實例
void func() {
cout << "mA:" << this->mA << endl;
}
//靜態成員函數也不佔對象空間
static void sfunc() {
}
};
int main() {
cout << sizeof(Person) << endl;
system("pause");
return 0;
}
1.2 this指針概念
通過4.3.1我們知道在C++中成員變量和成員函數是分開存儲的
每一個非靜態成員函數只會誕生一份函數實例,也就是說多個同類型的對象會共用一塊代碼
那麼問題是:這一塊代碼是如何區分那個對象調用自己的呢?
c++通過提供特殊的對象指針,this指針,解決上述問題。this指針指向被調用的成員函數所屬的對象
this指針是隱含每一個非靜態成員函數內的一種指針
this指針不需要定義,直接使用即可
this指針的用途:
- 當形參和成員變量同名時,可用this指針來區分
- 在類的非靜態成員函數中返回對象本身,可使用return *this
class Person
{
public:
Person(int age)
{
//1、當形參和成員變量同名時,可用this指針來區分
this->age = age;
}
Person& PersonAddPerson(Person p)
{
this->age += p.age;
//返回對象本身
return *this;
}
int age;
};
void test01()
{
Person p1(10);
cout << "p1.age = " << p1.age << endl;
Person p2(10);
p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);
cout << "p2.age = " << p2.age << endl;
}
int main() {
test01();
system("pause");
return 0;
}
1.3 空指針訪問成員函數
//空指針訪問成員函數
class Person {
public:
void ShowClassName() {
cout << "我是Person類!" << endl;
}
void ShowPerson() {
if (this == NULL) {
return;
}
cout << mAge << endl;
}
public:
int mAge;
};
void test01()
{
Person * p = NULL;
p->ShowClassName(); //空指針,可以調用成員函數
p->ShowPerson(); //但是如果成員函數中用到了this指針,就不可以了
}
int main() {
test01();
system("pause");
return 0;
}
1.4 const修飾成員函數
常函數:
-
成員函數後加const後我們稱爲這個函數爲常函數
-
常函數內不可以修改成員屬性
-
成員屬性聲明時加關鍵字mutable後,在常函數中依然可以修改
常對象: -
聲明對象前加const稱該對象爲常對象
-
常對象只能調用常函數
class Person {
public:
Person() {
m_A = 0;
m_B = 0;
}
//this指針的本質是一個指針常量,指針的指向不可修改
//如果想讓指針指向的值也不可以修改,需要聲明常函數
void ShowPerson() const {
//const Type* const pointer;
//this = NULL; //不能修改指針的指向 Person* const this;
//this->mA = 100; //但是this指針指向的對象的數據是可以修改的
//const修飾成員函數,表示指針指向的內存空間的數據不能修改,除了mutable修飾的變量
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修飾成員變量
//常對象訪問成員函數
person.MyFunc(); //常對象能調用const的函數
}
int main() {
test01();
system("pause");
return 0;
}
2.友元
生活中你的家有客廳(Public),有你的臥室(Private)
客廳所有來的客人都可以進去,但是你的臥室是私有的,也就是說只有你能進去
但是呢,你也可以允許你的好閨蜜好基友進去。
在程序裏,有些私有屬性 也想讓類外特殊的一些函數或者類進行訪問,就需要用到友元的技術
友元的目的就是讓一個函數或者類 訪問另一個類中私有成員
友元的關鍵字爲 friend
友元的三種實現
- 全局函數做友元
- 類做友元
- 成員函數做友元
2.1 全局函數做友元
class Building
{
//告訴編譯器 goodGay全局函數 是 Building類的好朋友,可以訪問類中的私有內容
friend void goodGay(Building * building);
public:
Building()
{
this->m_SittingRoom = "客廳";
this->m_BedRoom = "臥室";
}
public:
string m_SittingRoom; //客廳
private:
string m_BedRoom; //臥室
};
void goodGay(Building * building)
{
cout << "好基友正在訪問: " << building->m_SittingRoom << endl;
cout << "好基友正在訪問: " << building->m_BedRoom << endl;
}
void test01()
{
Building b;
goodGay(&b);
}
int main(){
test01();
system("pause");
return 0;
}
2.2 類做友元
class Building;
class goodGay
{
public:
goodGay();
void visit();
private:
Building *building;
};
class Building
{
//告訴編譯器 goodGay類是Building類的好朋友,可以訪問到Building類中私有內容
friend class goodGay;
public:
Building();
public:
string m_SittingRoom; //客廳
private:
string m_BedRoom;//臥室
};
Building::Building()
{
this->m_SittingRoom = "客廳";
this->m_BedRoom = "臥室";
}
goodGay::goodGay()
{
building = new Building;
}
void goodGay::visit()
{
cout << "好基友正在訪問" << building->m_SittingRoom << endl;
cout << "好基友正在訪問" << building->m_BedRoom << endl;
}
void test01()
{
goodGay gg;
gg.visit();
}
int main(){
test01();
system("pause");
return 0;
}
2.3 成員函數做友元
class Building;
class goodGay
{
public:
goodGay();
void visit(); //只讓visit函數作爲Building的好朋友,可以發訪問Building中私有內容
void visit2();
private:
Building *building;
};
class Building
{
//告訴編譯器 goodGay類中的visit成員函數 是Building好朋友,可以訪問私有內容
friend void goodGay::visit();
public:
Building();
public:
string m_SittingRoom; //客廳
private:
string m_BedRoom;//臥室
};
Building::Building()
{
this->m_SittingRoom = "客廳";
this->m_BedRoom = "臥室";
}
goodGay::goodGay()
{
building = new Building;
}
void goodGay::visit()
{
cout << "好基友正在訪問" << building->m_SittingRoom << endl;
cout << "好基友正在訪問" << building->m_BedRoom << endl;
}
void goodGay::visit2()
{
cout << "好基友正在訪問" << building->m_SittingRoom << endl;
//cout << "好基友正在訪問" << building->m_BedRoom << endl;
}
void test01()
{
goodGay gg;
gg.visit();
}
int main(){
test01();
system("pause");
return 0;
}