一、C++對象模型和this指針
1.1 成員變量和成員函數分開存儲
在C++中,類內的成員變量和成員函數分開存儲
只有非靜態成員變量才屬于類的對象
#include <iostream>using namespace std;class a1
{};class a2
{int a;
};class a3
{int a;static int b;
};class a4
{int a;void func(){}
};class a5
{int a;static void func(){}
};void test1()
{ a1 a1;// 空對象占用內存空間為1// C++編譯器會給每個空對象也分配一個字節空間,是為了區分空對象占內存的位置// 每個空對象也應該有一個獨一無二的內存地址cout << "size of t:" << sizeof(a1) << endl;
}void test2()
{a2 a2;// 4,說明非靜態成員變量屬于類的對象cout << "size of t:" << sizeof(a2) << endl;
}void test3()
{a3 a3;// 4,說明靜態成員變量不屬于類的對象cout << "size of t:" << sizeof(a3) << endl;
}void test4()
{a4 a4;// 4,說明非靜態成員函數不屬于類的對象cout << "size of t:" << sizeof(a4) << endl;
}void test5()
{a5 a5;// 4,說明靜態成員函數不屬于類的對象cout << "size of t:" << sizeof(a5) << endl;
}int main(int argc, char* argv[])
{test1();test2();test3();test4();test5();return 0;
}
1.2 this指針概念
每一個非靜態成員函數只會誕生一份函數實例,也就是說多個同類型的對象會共同一塊代碼,那么問題是:這一塊代碼是如何區分是哪個對象調用自己的呢?
C++通過提供特殊的對象指針,this指針,解決上述問題。this指針指向被調用的成員函數所屬的對象
this指針是隱含每一個非靜態成員函數內的一種指針
this指針不需要定義,直接使用即可
this指針的用途:
? ? ? ? 1. 當形參和成員變量名同名時,可用this指針來區分
#include <iostream>using namespace std;class Person
{
public:Person(int age){// age = age; 報錯this->age = age;}int age;
};void test()
{Person p(23);cout << "p1的年齡:" << p.age << endl;
}int main(int argc, char* argv[])
{test();return 0;
}
? ? ? ? 2. 在類的非靜態成員函數中返回對象本身,可使用return *this
#include <iostream>using namespace std;class Person
{
public:Person(int age){// age = age; 報錯this->age = age;}int age;Person addAge1(Person& p){this->age += p.age;return *this;}Person& addAge2(Person& p){this->age += p.age;return *this;}
};void test()
{Person p1(23);cout << "p1的年齡:" << p1.age << endl;Person p2(20);// addAge1返回的值,p1加完p2返回的是拷貝構造函數創建的新的對象,和自身不同,并沒有在p1上進行累加p1.addAge1(p2).addAge1(p2).addAge1(p2).addAge1(p2);cout << "p1的年齡:" << p1.age << endl;// addAge2返回的引用,p1加完p2,返回p2本身p1.addAge2(p2).addAge2(p2).addAge2(p2).addAge2(p2);cout << "p1的年齡:" << p1.age << endl;
}int main(int argc, char* argv[])
{test();return 0;
}
1.3 空指針訪問成員函數
C++中空指針也是可以調用成員函數的,但是也要注意有沒有用到this指針
如果用到this指針,需要加以判斷保證代碼的健壯性
#include <iostream>using namespace std;class Person
{
public:void showClassName(){cout << "this is Person class" << endl;}void showAge(){// 提高代碼健壯性if (this == NULL){return;}// this指針指向的Person是一個空指針,對象沒有實體,更不用說有age屬性了cout << "age=" << this->age << endl; // 在屬性的前面都默認加了this}int age;
};void test()
{Person* p = NULL;p->showClassName(); // 可以運行p->showAge(); // 有問題
}int main(int argc, char* argv[])
{test();return 0;
}
1.4?const修飾成員函數
常函數:1. 成員函數加const后我們稱這個函數為常函數
? ? ? ? ? ? ? 2. 常函數內不可以修改成員屬性
? ? ? ? ? ? ? 3. 成員屬性聲明時加關鍵字mutable后,在常函數中依然可以修改
常對象:1. 聲明對象前加const稱該對象為常對象
? ? ? ? ? ? ? 2. 常對象只能調用常函數?
二、友元
生活中家里有客廳(Public),有臥室(Private)
客廳所有來的客人都可以進去,但是你的臥室是私有的,也就是說只有你自己可以進去
但是,還有一些例外,比如你允許你的好朋友進去
在程序里,有些私有屬性也想讓類外特殊的一些函數或者類進行訪問,就需要用到友元技術
友元的目的就是讓一個函數或者類訪問另一個類中的私有成員
友元的關機字為 friend
友元的三種實現:1. 全局函數做友元
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2. 類做友元
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?3. 成員函數做友元
2.1 成員函數做友元
#include <iostream>
#include <string>using namespace std;class Building
{// 告訴編譯器,goodfriend是全局函數,是Building類的好朋友,可以訪問類中的私有內容friend void goodfriend(Building* building);public:Building(){this->m_SittingRoom = "客廳";this->m_BedRoom = "臥室";}public:string m_SittingRoom; // 客廳
private:string m_BedRoom; // 臥室
};void goodfriend(Building* building)
{cout << "正在訪問:" << building->m_SittingRoom << endl;cout << "正在訪問:" << building->m_BedRoom << endl;
}int main(int argc, char* argv[])
{Building building;goodfriend(&building);return 0;
}
2.2 類做友元
#include <iostream>
#include <string>using namespace std;class Building
{// 告訴編譯器,goodfriend是Building類的好朋友,可以訪問類中的私有內容friend class goodfriend;public:Building();
public:string m_SittingRoom; // 客廳
private:string m_BedRoom; // 臥室
};
// 類外寫成員函數
Building::Building()
{m_SittingRoom = "客廳";m_BedRoom = "臥室";
}class goodfriend
{
public:Building* building;goodfriend();void visit();
};
// 類外寫成員函數
goodfriend::goodfriend()
{// 創建建筑物對象building = new Building;
}
void goodfriend::visit()
{cout << "正在訪問:" << building->m_SittingRoom << endl;cout << "正在訪問:" << building->m_BedRoom << endl;
}void test()
{goodfriend zz;zz.visit();
}
int main(int argc, char* argv[])
{test();return 0;
}
2.3 成員函數做友元
#include <iostream>
#include <string>using namespace std;class Building;
class GoodFriend
{
public:Building* building;GoodFriend();void visit1(); // 讓visit1函數可以訪問Building中私有屬性void visit2(); // 讓visit2函數不能訪問Building中私有屬性
};class Building
{// 告訴編譯器,goodfriend是Building類的好朋友,可以訪問類中的私有內容friend void GoodFriend::visit1();public:Building();
public:string m_SittingRoom; // 客廳
private:string m_BedRoom; // 臥室
};
// 類外寫成員函數
Building::Building()
{m_SittingRoom = "客廳";m_BedRoom = "臥室";
}// 類外寫成員函數
GoodFriend::GoodFriend()
{// 創建建筑物對象building = new Building;
}
void GoodFriend::visit1()
{cout << "正在訪問:" << building->m_SittingRoom << endl;cout << "正在訪問:" << building->m_BedRoom << endl;
}
void GoodFriend::visit2()
{cout << "正在訪問:" << building->m_SittingRoom << endl;// cout << "正在訪問:" << building->m_BedRoom << endl;
}
void test()
{GoodFriend gf;gf.visit1();gf.visit2();
}
int main(int argc, char* argv[])
{test();return 0;
}