2020-02-14 C++核心編程03-基本框架

4.2.8靜態(tài)成員

靜態(tài)成員變量

1.所有對象共享同一份數(shù)據(jù);

2.在編譯階段分配內(nèi)存;

3.類內(nèi)聲明,類外初始化;

示例:

class Person

{

public:

public:

static int _A;

//靜態(tài)成員變量,不屬于某個對象上,所有對象都共享同一個數(shù)據(jù)

//靜態(tài)成員變量具有兩種訪問方式

//1.通過對象進行訪問

//2.通過類名進行訪問

//靜態(tài)成員變量也是有訪問權(quán)限的

private:

static int _B;//類內(nèi)聲明

};

int Person::_A=100;

int Person::_B = 200;//類外初始化

void test02()

{

//通過類名訪問靜態(tài)成員變量

cout << Person::_A << endl;

//cout << Person::_B << endl;類外訪問不到私有(保護)靜態(tài)成員變量

}

靜態(tài)成員函數(shù)

1.所有對象共享同一個函數(shù);

2.靜態(tài)成員函數(shù)只能訪問靜態(tài)成員變量;

示例:

class Person

{

public:

static void func()//靜態(tài)成員函數(shù)也是有訪問權(quán)限的

{

_A = 100;//靜態(tài)成員函數(shù)可以訪問 靜態(tài)成員變量

//_B = 200;//靜態(tài)成員函數(shù)不可以訪問 非靜態(tài)成員變量

? ? ? ? //因為無法區(qū)分到底是哪個對象的_B

cout << "static void func()" << endl;

}

public:

static int _A;

int _B;

private:

static void func2()

{

cout << "static void func2()" << endl;

}

};

int Person::_A = 0;

void test01()

{

Person p;

p.func();//1.通過對象訪問

cout << "-------" << endl;

Person::func();//2.通過類名訪問

}

void test02()

{

//Person::func2();//類外訪問不到私有的靜態(tài)成員函數(shù)

}

4.3C++對象模型和this指針

4.3.1成員變量和成員函數(shù)分開存儲

只有非靜態(tài)成員變量才屬于類的對象上

4.3.1this指針

每個非靜態(tài)成員函數(shù)只會誕生一份函數(shù)實例,也就是說多個同類型的對象會共用一塊代碼

C++通過提供特殊的對象指針,this指針,能夠使得代碼區(qū)分調(diào)用自己的對象

概念:

1.this指針指向被調(diào)用的成員函數(shù)所屬的對象;

2.this指針是隱含每一個非靜態(tài)成員函數(shù)的一種指針;

3.this指針不需要定義,直接使用即可;

用途:

1.當形參和成員變量同名時,可用this指針來區(qū)分;(解決名稱沖突)

2.在類的非靜態(tài)成員函數(shù)中返回對象本身,可使用 return *this;

示例:

class Person

{

public:

Person(int age)

{

//1.解決名稱沖突

//age = age;//error ,編譯器認為兩個age是同一個,即形參age

//this指針指向的是被調(diào)用成員函數(shù)所屬的對象

this->age = age;

}

void PersonAddAge(Person &p)

{

this->age += p.age;

}

//易錯點

//Person PersonAddAge2(Person &p)

//error

Person & PersonAddAge2(Person &p)

{

this->age += p.age;

//this是指向p2的指針,而*this就是p2這個對象本體

return *this;

}

Person? PersonAddAge3(Person &p)

{

this->age += p.age;

//this是指向p2的指針,而*this就是p2這個對象本體

return *this;

}

int age;

};

void test01()

{

Person p1(18);

cout << "the age of p1 is " << p1.age << endl;

}

//2.返回對象本身用*this

void test02()

{

Person p1(10);

Person p2(10);

p2.PersonAddAge(p1);

cout << "the age of p2 is " << p2.age << endl;

//p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);

//error

}

void test03()

{

Person p1(10);

Person p2(10);

p2.PersonAddAge2(p1);

cout << "the age of p2 is " << p2.age << endl;

//鏈式編程思想

p2.PersonAddAge2(p1).PersonAddAge2(p1).PersonAddAge2(p1);

cout << "the age of p2 is " << p2.age << endl;

}

void test04()

{

Person p1(10);

Person p2(10);

p2.PersonAddAge3(p1);//p2.age更改,但函數(shù)返回的是p2的拷貝

? ? ? ? ? ? ? ? ? ? //此時p2.age=20

cout << "the age of p2 is " << p2.age << endl;

//第一個函數(shù)更改了p2.age 但返回的是p2的拷貝 記為 p2’

//第二個函數(shù)更改的是p2’

//第三個函數(shù)更改的是p2''

//所以p2.age=30

p2.PersonAddAge3(p1).PersonAddAge3(p1).PersonAddAge3(p1);

cout << "the age of p2 is " << p2.age << endl;

}

4.3.3空指針訪問成員函數(shù)

C++中空指針也可以調(diào)用成員函數(shù),但要注意有沒有用到this指針

如果用到this指針,需要加以判斷保證代碼健壯性

示例:

class Person

{

public:

//空指針可以正常訪問

void showClassName()

{

cout << "this is Person class" << endl;

}

void showPersonAge()

{

//報錯原因是因為傳入的指針為NULL

cout << "age is " << m_Age << endl;

//m_Age默認為this->m_Age

}

void showPersonAge2()

{

//提高代碼健壯性

if (this == NULL)

{

return;

}

cout << "age is " << m_Age << endl;

}

int m_Age;

};

void test01()

{

Person *p = NULL;

p->showClassName();

//p->showPersonAge();

//error

p->showPersonAge2();

}

4.3.4const修飾成員函數(shù)

常函數(shù):

1.成員函數(shù)后加const后我們稱這個函數(shù)為常函數(shù);

2.常函數(shù)內(nèi)不可以修改成員屬性;

3.成員屬性聲明時加關(guān)鍵字mutable后,在常函數(shù)中依然可以修改

常對象:

1.聲明對象前加const稱該對象為常對象;

2.常對象只能調(diào)用常函數(shù);

示例:

class Person

{

public:

void showPerson1()

{

//this指針本質(zhì)是指針常量,指針的指向是不可以修改的

//Person * const this;

this->m_A = 100;//this指針指向的內(nèi)容可以修改

//this = NULL;//this指針不可以修改指針指向

}

//在成員函數(shù)后面加上const 修飾的是this指針,讓指針指向的值也不可以修改

void showPerson2() const? //常函數(shù)

{

//如果想要this指針指向的值也不可以修改

//把const加在成員函數(shù)后

//就相當于const Person * const this;

? ? //this->m_A = 100;//error

this->m_B = 100;//ok

}

public:

int m_A;

mutable int m_B;//特殊變量,即使在常函數(shù)中,也可以修改這個值

? ? ? ? ? ? ? ? //加關(guān)鍵字mutable

};

void test01()

{

//常對象

const Person p;

//p.m_A = 100;//error

p.m_B = 100;//ok ,m_B是特殊值,在常對象下也可以修改

? ? //常對象只能調(diào)用常函數(shù)

//不可以調(diào)用普通成員函數(shù),因為普通成員函數(shù)可以修改屬性

//p.showPerson1();//error

p.showPerson2();//ok

}


4.4友元

目的:讓一個函數(shù)或類 訪問另一個類中的私有成員

關(guān)鍵字:friend

友元的三種實現(xiàn):

1.全局函數(shù)做友元函數(shù)

2.類做友元類

3.類的成員函數(shù)做友元

4.5運算符重載

概念:對已有的運算符重新進行定義,賦予其另一種功能,以適應(yīng)不同的數(shù)據(jù)類型

4.5.1加號運算符重載

作用:實現(xiàn)兩個自定義數(shù)據(jù)類型相加的運算

兩種方式:

1.成員函數(shù)重載

2.全局函數(shù)重載

示例:

class Person

{

public:

//Person operator+(Person &p);//1.成員函數(shù)重載

Person(){}

Person(int a, int b);

public:

int m_A;

int m_B;

};

//Person Person::operator+(Person &p)

//{

// Person temp;

// temp.m_A=this->m_A + p.m_A;

// temp.m_B=this->m_B + p.m_B;

// return temp;

//}

Person::Person(int a, int b)

{

m_A = a;

m_B = b;

}

//2.全局函數(shù)重載

Person operator+(Person &p1, Person &p2)

{

Person temp;

temp.m_A = p1.m_A + p2.m_A;

temp.m_B = p1.m_B + p2.m_B;

return temp;

}

//運算符重載,也可以發(fā)生函數(shù)重載

//函數(shù)重載的版本

Person operator+(Person &p1, int a)

{

Person temp;

temp.m_A = p1.m_A + a;

temp.m_B = p1.m_B + a;

return temp;

}

void test00()

{

Person p1(10, 10);

Person p2 = p1 + 10;

cout << "p2.m_A=" << p2.m_A << endl

<< "p2.m_B=" << p2.m_B << endl;

}

void test01()

{

Person p1(10, 10);

Person p2(20, 20);

Person p3 = p1 + p2;

//1.成員函數(shù)重載的本質(zhì)調(diào)用

//Person p3=p1.operator+(p2);

//2.全局函數(shù)重載的本質(zhì)調(diào)用

//Person p3=operator+(p1,p2);

}

總結(jié):

1.對于內(nèi)置的數(shù)據(jù)類型的表達式的運算符是不可能改變的;

2.不要濫用運算符重載;

4.5.2左移運算符重載

作用:輸出自定義數(shù)據(jù)類型

注意:只能通過全局函數(shù)重載輸出流運算符,且需要設(shè)置為類的友元函數(shù)

示例:

class Person

{

//將全局函數(shù)設(shè)置為友元

friend ostream & operator<<(ostream &os, Person &p);

public:

//利用成員函數(shù)重載 左移運算符 p.operator<<(cout) 簡化版本 p<<cout

//不會利用成員函數(shù)重載<<運算符 ,因為無法實現(xiàn)cout在左側(cè)

//void operator<<(cout ){}

? ? Person(int a, int b)

{

m_A = a;

m_B = b;

}

private:

int m_A;

int m_B;

};

//只能利用全局函數(shù)重載左移運算符

//void? operator<<(ostream &cout,Person &p)//本質(zhì) operator<<(cout,p) 簡化 cout<<p

//{

// cout << "m_A=" << p.m_A << endl

// << "m_B=" << p.m_B << endl;

//}

//ostream 也是一種類

//ostream對象只能有一個,所以需要加&

ostream & operator<<(ostream &os, Person &p)//本質(zhì) operator<<(cout,p) 簡化 cout<<p

{

os << "m_A=" << p.m_A <<"? "

<< "m_B=" << p.m_B ;

return os;

}

void test01()

{

Person p(10,10);

//cout << p ;

cout<<p<<endl;

//返回值為void時,上一行程序會崩掉

//由于左側(cè)返回的是void ,不能實現(xiàn)鏈式編程

//因此需要對左移運算符重載函數(shù)進行返回值的修改

}

總結(jié):重載左移運算符配合友元可以實現(xiàn)輸出自定義數(shù)據(jù)類型

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容