最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C++const成員、static成員、成員函數(shù)指針、友元

2023-09-10 20:06 作者:虛云幻仙  | 我要投稿

#include <iostream>

using namespace std;


class Classconst

{

????public:

???? const int i1; //const數(shù)據(jù)成員,c++要求const類型必須顯式初始化,當(dāng)構(gòu)造函數(shù)執(zhí)行到函數(shù)體{}時對象及其成員已經(jīng)被聲明了,所以const成員無法在函數(shù)體內(nèi)初始化

???? Classconst(int val=5) //默認(rèn)參數(shù)兼顧無參構(gòu)造器

???? :i1(val),i2(i1) //const限定的數(shù)據(jù)成員一般通過成員初始化列表進(jìn)行初始化,格式為: 構(gòu)造函數(shù)():數(shù)據(jù)成員(值){函數(shù)體} ,初始化寫在塊前面、形參列表后面以冒號開頭,(對于成員對象來說)效率比在塊中賦值高(因為進(jìn)入塊之前需要默認(rèn)初始化,進(jìn)入塊后再執(zhí)行賦值運算符重載,而直接通過拷貝構(gòu)造器省一次函數(shù)調(diào)用),使用這種方式時如果數(shù)據(jù)成員之間相互賦值(如成員c=成員b),則類中b的聲明需要在c前面/上面才對c可見,這也表明成員的初始化順序是按類中聲明的順序,在聲明、初始化上一個成員時,下一個成員還不存在所以不可見,注意初始化列表中各項的先后順序與初始化順序無關(guān)

???? {}

???? void dis() //普通函數(shù)成員

???? {

???????? i2 = 3;

???????? cout << i1 << endl;

???? }

???? void dis() const //const函數(shù)成員,格式為:函數(shù)頭 const {函數(shù)體} ,聲明const函數(shù)成員保證函數(shù)內(nèi)不修改數(shù)據(jù)成員,包括函數(shù)的子塊、調(diào)用的函數(shù),調(diào)用的函數(shù)也必須為const函數(shù),const函數(shù)與普通函數(shù)構(gòu)成重載

???? {

???????? //i2 = 3; 不能修改i2

???????? //geti2(); 不能調(diào)用非const函數(shù)

???????? cout << i1 << endl;

???????? cout << i2 << endl; //可以使用非const數(shù)據(jù)成員

???????? int local = 20;

???????? local = 40; //數(shù)據(jù)成員外的變量不受const約束

???? }

???? int i3;

???? void geti2()

???? {

???? ????cout << i2;

???? }

????private:

???? int i2 = 2; //c++11類內(nèi)初始化(之前版本不允許)等價于成員初始化列表,該成員會默認(rèn)初始化為指定值,如果構(gòu)造器初始化列表設(shè)定了該成員的初始化則類內(nèi)初始化不起作用(被覆蓋)

};

int mainconst()

{

???? Classconst c(20);

???? c.dis(); //非const對象優(yōu)先調(diào)用非const函數(shù),當(dāng)沒有普通函數(shù)時調(diào)用const函數(shù)

???? const Classconst c2; //const 對象

???? //錯誤:c2.geti2(); const對象只能調(diào)用const函數(shù)

???? c2.dis(); //調(diào)用的是dis() const函數(shù),

???? c2.i3; //可訪問非const數(shù)據(jù)

???? //錯誤:c2.i3 = 30; const對象不能修改任何成員

????

???? int i1=10,i2=20;

???? -i1; //分析int類型變量的operator-() 負(fù)號運算符,取負(fù)不影響原變量

???? i1 = -i1; //-i1可以作為右值(用于賦值)

???? //報錯:-i1 = i2; //-i1不可作為左值(不可修改)

???? -(-i1); //可以對-i1再取負(fù)數(shù),而這個過程不能改變-i1本身

???? //所以-i1產(chǎn)生了一個使用i1數(shù)據(jù)進(jìn)行運算的備份,而這個備份const不可修改,但可以對這個const再產(chǎn)生新的備份

???? return 0;

}

class ClassNum //模擬取負(fù)的邏輯

{

????public:

???? int v1;

???? int v2;

???? ClassNum(int a, int b) :v1(a), v2(b) {}

???? //const ClassNum operator-() //返回const對象,對應(yīng)-c1,返回一個const備份(通過對c1取負(fù)),返回對象用到默認(rèn)的拷貝構(gòu)造器(不涉及堆內(nèi)存/動態(tài)內(nèi)存則不需要手動定義)

???? //{

???? ????// return ClassNum(-v1, -v2); //創(chuàng)建一個新的對象,使用當(dāng)前對象的數(shù)據(jù)取負(fù)。創(chuàng)建對象使用了兩個參數(shù)的構(gòu)造器,返回對象使用了拷貝構(gòu)造器,所以調(diào)用時總共會額外創(chuàng)建兩個對象

???? //}

???? //上面的函數(shù)可以完成-c1;c1=-c1;以及不允許-c1=c2三項。但是-(-c1)不行,因為-c1返回了const對象,const對象不能調(diào)用非const函數(shù)。所以應(yīng)該修改該函數(shù)為const函數(shù)

???? const ClassNum operator-() const //將函數(shù)聲明為const,普通對象可以訪問,const對象也可以訪問

???? {

???? ????return ClassNum(-v1, -v2);

???? }

???? int norint; //普通成員變量,當(dāng)對象聲明為const時不能修改對象的成員

???? mutable int mutint; //mutable關(guān)鍵字修飾的成員,即便是在const對象/結(jié)構(gòu)變量中也可以修改

};


class Cow

{

???? char name[20];

???? char* hobby;

???? double weight;

????public:

???? Cow() :name(""), hobby(nullptr), weight(0.0) {} //成員初始化列表,在創(chuàng)建對象、聲明成員時進(jìn)行初始化,執(zhí)行到函數(shù)體{}中對象已經(jīng)進(jìn)行了默認(rèn)的或指定的初始化,在函數(shù)體中進(jìn)行的為賦值而非初始化,通過name("")就可看出,等價于聲明成員name=""(char數(shù)組只在初始化時可以=字符串常量),而將hobby初始化為nullptr(c++關(guān)鍵字,等價于NULL和0,專門指代空指針),通過列表初始化時不能使用this,也就是說這里的初始化發(fā)生在產(chǎn)生對象之前

???? ~Cow() { delete[]hobby; } //hobby==nullptr時也可以delete[]hobby

???? Cow(const char* nm, const char* ho, double wt) :weight(wt)

???? {

???????? strncpy(name, nm, 19);

???????? name[19] = 0;

???????? hobby = new char[strlen(ho) + 1];

???????? strcpy(hobby, ho);

???? }

???? Cow(const Cow& c) :weight(c.weight)

???? {

???????? strcpy(name, c.name);

???????? if (c.hobby) //需要判斷hobby!=nullptr,雖然為空指針時可以delete[]hobby,但調(diào)用strlen等不接收nullptr的函數(shù)會出錯

???????? {

???????????? hobby = new char[strlen(c.hobby) + 1];

???????????? strcpy(hobby, c.hobby);

???????? }

???????? else

???????? {

???????? ????hobby = nullptr;

???????? }

???? }

???? Cow& operator=(const Cow& c)

???? {

???????? delete[]hobby;

???????? weight = c.weight; //賦值運算符重載無法使用成員初始化列表,因為this是已存在對象

???????? strcpy(name, c.name);

???????? if (c.hobby) //如果將hobby默認(rèn)設(shè)置為new char[1],hobby[0]=0則調(diào)用strlen不會出錯,但默認(rèn)構(gòu)造會占用堆內(nèi)存

???????? {

???????????? hobby = new char[strlen(c.hobby) + 1];

???????????? strcpy(hobby, c.hobby);

???????? }

???????? else

???????? {

???????? ????hobby = nullptr;

???????? }

???????? return *this;

???? }

???? void ShowCow()const //const函數(shù)兼容const對象

???? {

???? ????cout << "name:" << (name[0] ? name : "none") << "\thobby:" << (hobby ? hobby : "none") << "\tweight:" << weight << endl;

???? }

};


/*------ClassStatic.h頭文件--------*/

class ClassStatic

{

????public:

???? ~ClassStatic();

???? static int count; //static數(shù)據(jù)成員,屬于類、唯一,對象可調(diào)用,使用前必須在類以外的地方聲明

???? static const int SIZE = 16; //static const 同時修飾數(shù)據(jù)成員,既屬于類、唯一,又不可修改。只能像這樣在聲明時進(jìn)行初始化

???? ClassStatic(char v = '\0')

???? {

???????? if (count < SIZE) //通過對象調(diào)用static成員

???????? stack[count++] = v; //改變static成員

???? }

???? static void reset() //static函數(shù)成員,屬于類,可通過類調(diào)用,也可由對象調(diào)用,所以沒有this指針,也就是說不能在函數(shù)中訪問屬于對象的數(shù)據(jù)/函數(shù)成員,static函數(shù)只能訪問static數(shù)據(jù)/函數(shù)

???? {

???? ????count = 0;

???? }

???? int data;

???? void func() {}

????private:

???? static char* stack; //static私有成員也在類外聲明才能使用,但除聲明外不能直接訪問(因為私有),類中的static聲明就像是名稱空間中的引用式聲明外部鏈接變量,如果在頭文件中的類聲明中使用了定義式聲明(初始化一個靜態(tài)成員或者寫一個函數(shù)定義),當(dāng)多個源文件都包含該頭文件時會產(chǎn)生多重定義沖突,所以在類聲明中只聲明,在同名cpp文件中進(jìn)行定義

???? int va;

};



/*------ClassStatic.cpp文件--------*/

ClassStatic::~ClassStatic() {} //析構(gòu)略

int ClassStatic::count = 0; //在cpp文件中完成類的靜態(tài)成員的定義式聲明,同樣只能存在一個定義式聲明,靜態(tài)變量不顯式初始化會初始化為0。類的靜態(tài)成員在頭文件、源文件中的引用式聲明、定義式聲明就像名稱空間中的靜態(tài)變量用法一樣

char arr[ClassStatic::SIZE]; //類外使用static const常量

char* ClassStatic::stack = arr; //所有static成員都必須在類外聲明(包括私有的),在類的頭文件配套的cpp文件中聲明,除該聲明外不能直接訪問(因為私有)


/*------用戶使用.cpp文件--------*/

int mainstatic()

{

???? ClassStatic::count = 2; //通過類訪問static成員,這時還沒有創(chuàng)建對象,static成員屬于類

???? //錯誤:ClassStatic::stack;私有不可訪問

???? ClassStatic c;

???? c.reset(); //通過對象調(diào)用static函數(shù)

???? c.count = 5; //通過對象調(diào)用static數(shù)據(jù)

???? ClassStatic::reset(); //通過類調(diào)用static函數(shù)

???? //static成員相當(dāng)于是類的名稱空間下的全局變量,全局/靜態(tài)變量從程序開始到結(jié)束一直存在,所以初始化非0的全局/靜態(tài)變量(RW-data)(read write)隨代碼(code/text)以及常量(RO-data)(read only 只讀的靜態(tài)/全局變量)保存在ROM(硬盤等)的程序文件中,所以載入文件/程序運行后將全局/靜態(tài)變量讀取到RAM(內(nèi)存)即可使用,而未初始化或初始化為0的全局/靜態(tài)變量(ZI-data/.bss)(zero init)只需要記錄大小,在程序運行前開辟好空間備用。所以全局/靜態(tài)變量的大小是固定的,程序執(zhí)行之前就知道應(yīng)該開辟多大,也就不存在溢出的問題

???? //而普通數(shù)據(jù)成員屬于對象,在函數(shù)/棧中創(chuàng)建自動類型變量時每個對象大小為其非靜態(tài)數(shù)據(jù)成員的總和,由于棧有最大限制,如果棧內(nèi)變量過多(如大數(shù)組)可能導(dǎo)致棧溢出。

???? //動態(tài)內(nèi)存/堆的大小隨malloc/free等函數(shù)而變化

????

???? int ClassStatic::* pd = &ClassStatic::data; //聲明一個指向普通數(shù)據(jù)成員的指針,pd的類型為(int ClassStatic::*) 整體

???? //作用域解析運算符優(yōu)先級最高,所以賦值運算符右側(cè)等價于&(ClassStatic::data)

???? //在這個聲明中沒有使用某一個對象,所以成員指針pd只記錄了成員在類中的位置

???? c.data = 5; //正常調(diào)用

???? c.*pd = 10; //通過指針調(diào)用,這里運算符 .* 為一個運算符,pd實際記錄了成員在類中的偏移量信息,c.*pd通過計算偏移量訪問指向的區(qū)域

???? //普通的指針 類型名 * 指針=&變量

???? //指向成員的 類型名 類名::* 指針 = &類名::成員

???? //成員指針可以更改指向相同類型的成員,這里pd類型為(int ClassStatic::*),可以指向類ClassStatic中任意int數(shù)據(jù)成員

???? void (ClassStatic::* pf)() = &ClassStatic::func; //聲明指向函數(shù)成員的指針

???? //類名::* 是一個整體,需要和函數(shù)成員指針括在一起,即 函數(shù)簽名部分 (類名::* 指針)函數(shù)簽名部分。給函數(shù)成員指針賦值必須使用 &函數(shù)名 取址,不同于普通函數(shù)名賦值

???? c.func(); //正常調(diào)用

???? (c.*pf)(); //通過指針調(diào)用,運算符.*優(yōu)先級低于(),需要將 對象.*指針 作為整體括起來

???? //普通的指針 類型名 (*指針)() = [&]函數(shù)名

???? //指向成員的 類型名 (類名::*指針)() = &類名::函數(shù)

???? ClassStatic* pc = new ClassStatic; //在堆中創(chuàng)建對象

???? pc->*pd; //運算符->* 同樣為一個整體

???? (pc->*pf)(); //運算符->*優(yōu)先級同樣低于()

???? //(this->*pf)() 如果是在成員函數(shù)內(nèi)也可以使用this指針加成員指針使用

???? //結(jié)構(gòu)的大小是成員的和,結(jié)構(gòu)訪問成員是 結(jié)構(gòu)名.字段名 可以理解為 結(jié)構(gòu)變量的地址+偏移量 按類型進(jìn)行讀取和解釋

???? //類的大小是成員的和,可以理解為 對象名.成員名 同樣是對象地址+偏移量 按類型大小進(jìn)行讀取,按類型進(jìn)行解釋

???? //.* ->* 也理解為偏移量

????delete pc;

???? return 0;

}


class ClassFriend

{

????public:

???? enum

???? {

???? ????FUNC_ARRAY_SIZE = 5, MAX_ITEM = 1024

???? }; //在類內(nèi)使用枚舉,把類中需要使用的常量集中管理,優(yōu)于逐個const static,方便查找修改,不需要命名枚舉類型,這個枚舉屬于類,不占對象空間,類外通過類::訪問

???? void (*func[FUNC_ARRAY_SIZE])(); //效果同func[5]

???? friend void getmember(ClassFriend& obj); //友元函數(shù),通過友元可無視訪問限制直接訪問對象的私有、公有成員,在其他名稱空間定義、使用,這里聲明的是全局函數(shù),等價于 ::getmember

????private:

???? int mem;

};

void getmember(ClassFriend& obj) //把友元函數(shù)定義為全局函數(shù),因為不屬于ClassFriend類及對象(即沒有this指針),所以需要把對象傳進(jìn)來

{

???? obj.mem = 20;

???? cout << obj.mem << endl;

???? //友元全局函數(shù)需要在類中聲明,將函數(shù)原型寫在類中,不在類外再次聲明函數(shù)原型,如果在類中直接定義友元全局函數(shù)則為內(nèi)聯(lián)的友元全局函數(shù)

}

int mainfriend1()

{

???? ClassFriend c;

???? //錯誤:c.mem = 30;私有不可訪問

???? getmember(c); //通過友元函數(shù)訪問

???? return 0;

}


class ClassFriend1; //前向聲明

class ClassFManage1 //把友元成員函數(shù)定義在另一個類中

{

????public:

???? void getmember(ClassFriend1& obj); //通過CFM1對象.getmember()訪問CF1對象的私有成員,因為函數(shù)形參中需要用到ClassFriend1類型,所以需要在上面前向聲明這個類

};

class ClassFriend1

{

????private:

???? friend void ClassFManage1::getmember(ClassFriend1& obj); //CFM1類的函數(shù)所以要寫名稱空間,因為用到了CFM1::getmember()函數(shù),所以要在上面聲明這個函數(shù),這里不能只在上面寫類{這個函數(shù)的聲明}而在下面寫完整的類聲明。只能將友元函數(shù)所屬的類完整聲明在上面。這意味著兩個類不能相互包含友元成員函數(shù)

???? //friend關(guān)鍵字不受private等限制,可寫在類中任意位置不受影響

???? int mem;

};

void ClassFManage1::getmember(ClassFriend1& obj) //友元函數(shù)的實現(xiàn)因為要用到CF1對象的屬性,所以又必須放在CF1類的聲明的下面(因為前向聲明沒有聲明數(shù)據(jù)成員)

{

???? obj.mem = 30;

???? cout << obj.mem << endl;

}

//所以書寫順序為:先引用CF1類-再聲明CFM1類-再聲明CF1類(內(nèi)含friend CFM1::函數(shù))-再實現(xiàn)CFM1::函數(shù)

int mainfriend2()

{

???? ClassFriend1 c;

???? ClassFManage1 m;

???? m.getmember(c); //通過m訪問c的私有成員

???? return 0;

}


class ClassFriend2

{

????public:

???? friend class ClassFManage2; //友元類,使用友元類則不需要前面先聲明類CFM再在前面引用類CF

????private:

???? int mem;

};

class ClassFManage2 //友元類中所有函數(shù)都可以通過CF2對象訪問成員

{

????public:

???? void getmember(ClassFriend2& obj);

};


void ClassFManage2::getmember(ClassFriend2& obj)

{

???? obj.mem = 40;

???? cout << obj.mem << endl;

}

int mainfriend3()

{

???? ClassFriend2 c;

???? ClassFManage2 m;

???? m.getmember(c);

???? return 0;

}


class ClassFriend3

{

????public:

???? friend ClassFriend3 operator+(ClassFriend3& c1, ClassFriend3& c2); //使用友元重載+運算符

???? //ClassFriend3 operator+(ClassFriend3& c); //之前使用類的函數(shù)實現(xiàn)+運算符,兩種方法會產(chǎn)生二義性,因為表現(xiàn)形式均為c1+c2

????private:

???? int mem;

};


class ClassFriend4

{

???? double value_;

????public:

???? ClassFriend4(double value = 0) :value_(value) {}

???? void display1()const { cout << value_ << endl; } //公共接口,打印值,因為不修改*this對象所以函數(shù)const以兼容const對象

???? friend void display2(const ClassFriend4& cf4) { cout << cf4.value_ << endl; } //友元全局內(nèi)聯(lián)函數(shù),通過友元訪問私有成員

};

inline void display3(const ClassFriend4& cf4) { cf4.display1(); } //內(nèi)聯(lián)的非友元函數(shù),通過調(diào)用類接口函數(shù)來訪問私有成員


class CLSFa

{

???? friend class CLSFb; //fa和fb相互為友元

???? int da;

????public:

???? void setfb(CLSFb& obj); //因為前面有friend聲明所以參數(shù)可以使用CLSFb類型,但這里該類的成員不可見,所以要把定義放在CLSFb類聲明的后面或者.cpp文件中,如果想內(nèi)聯(lián)可以使用inline定義

};

class CLSFb

{

???? friend class CLSFa; //互相友元

???? int db;

????public:

???? void setfa(CLSFa& obj) //因為上面有CLSFa類的成員的聲明,所以這里可以直接寫定義

???? {

???? ????obj.da = 20;

???? }

};

inline void CLSFa::setfb(CLSFb& obj) //通過inline內(nèi)聯(lián)

{

????obj.db = 30;

}


//聲明兩個類共同的友元

class CLSfs1; //前向聲明其中一個類

class CLSfs2

{

???? friend void sync1to2(const CLSfs1& fs1, CLSfs2& fs2); //1to2需要兩個類的類型,因為是friend聲明在一個類中了所以還需要另一個前向聲明,通過這個語句只能知道1to2可以訪問fs2的私有

???? friend void sync2to1(const CLSfs2& fs2, CLSfs1& fs1); //調(diào)換參數(shù)順序

???? int t=20;

};

class CLSfs1

{

???? friend void sync1to2(const CLSfs1& fs1, CLSfs2& fs2); //到這里才知道函數(shù)既可訪問fs2私有也可訪問fs1私有

???? friend void sync2to1(const CLSfs2& fs2, CLSfs1& fs1);

???? int t=30;

};

void sync1to2(const CLSfs1& fs1, CLSfs2& fs2) //全局友元

{

????fs2.t = fs1.t;

}

void sync2to1(const CLSfs2& fs2, CLSfs1& fs1)

{

fs1.t = fs2.t;

}


C++const成員、static成員、成員函數(shù)指針、友元的評論 (共 條)

分享到微博請遵守國家法律
汝城县| 康平县| 宣城市| 南和县| 汨罗市| 江安县| 黑水县| 江津市| 揭阳市| 邹城市| 安泽县| 休宁县| 和龙市| 林西县| 孟村| 纳雍县| 浦城县| 罗源县| 南通市| 万州区| 贡嘎县| 治县。| 滁州市| 武强县| 华阴市| 莱芜市| 白水县| 灯塔市| 册亨县| 青阳县| 桂林市| 营口市| 长泰县| 夏河县| 夏邑县| 青海省| 西吉县| 周至县| 灵璧县| 宝鸡市| 马尔康县|