4.2.8靜態(tài)成員
靜態(tài)成員變量
1.所有對(duì)象共享同一份數(shù)據(jù)贤壁;
2.在編譯階段分配內(nèi)存;
3.類內(nèi)聲明,類外初始化;
示例:
class Person
{
public:
public:
static int _A;
//靜態(tài)成員變量颠通,不屬于某個(gè)對(duì)象上,所有對(duì)象都共享同一個(gè)數(shù)據(jù)
//靜態(tài)成員變量具有兩種訪問(wèn)方式
//1.通過(guò)對(duì)象進(jìn)行訪問(wèn)
//2.通過(guò)類名進(jìn)行訪問(wèn)
//靜態(tài)成員變量也是有訪問(wèn)權(quán)限的
private:
static int _B;//類內(nèi)聲明
};
int Person::_A=100;
int Person::_B = 200;//類外初始化
void test02()
{
//通過(guò)類名訪問(wèn)靜態(tài)成員變量
cout << Person::_A << endl;
//cout << Person::_B << endl;類外訪問(wèn)不到私有(保護(hù))靜態(tài)成員變量
}
靜態(tài)成員函數(shù)
1.所有對(duì)象共享同一個(gè)函數(shù)膀懈;
2.靜態(tài)成員函數(shù)只能訪問(wèn)靜態(tài)成員變量顿锰;
示例:
class Person
{
public:
static void func()//靜態(tài)成員函數(shù)也是有訪問(wèn)權(quán)限的
{
_A = 100;//靜態(tài)成員函數(shù)可以訪問(wèn) 靜態(tài)成員變量
//_B = 200;//靜態(tài)成員函數(shù)不可以訪問(wèn) 非靜態(tài)成員變量
? ? ? ? //因?yàn)闊o(wú)法區(qū)分到底是哪個(gè)對(duì)象的_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.通過(guò)對(duì)象訪問(wèn)
cout << "-------" << endl;
Person::func();//2.通過(guò)類名訪問(wèn)
}
void test02()
{
//Person::func2();//類外訪問(wèn)不到私有的靜態(tài)成員函數(shù)
}
4.3C++對(duì)象模型和this指針
4.3.1成員變量和成員函數(shù)分開(kāi)存儲(chǔ)
只有非靜態(tài)成員變量才屬于類的對(duì)象上
4.3.1this指針
每個(gè)非靜態(tài)成員函數(shù)只會(huì)誕生一份函數(shù)實(shí)例,也就是說(shuō)多個(gè)同類型的對(duì)象會(huì)共用一塊代碼
C++通過(guò)提供特殊的對(duì)象指針,this指針撵儿,能夠使得代碼區(qū)分調(diào)用自己的對(duì)象
概念:
1.this指針指向被調(diào)用的成員函數(shù)所屬的對(duì)象乘客;
2.this指針是隱含每一個(gè)非靜態(tài)成員函數(shù)的一種指針;
3.this指針不需要定義淀歇,直接使用即可;
用途:
1.當(dāng)形參和成員變量同名時(shí)匈织,可用this指針來(lái)區(qū)分浪默;(解決名稱沖突)
2.在類的非靜態(tài)成員函數(shù)中返回對(duì)象本身,可使用 return *this缀匕;
示例:
class Person
{
public:
Person(int age)
{
//1.解決名稱沖突
//age = age;//error 纳决,編譯器認(rèn)為兩個(gè)age是同一個(gè),即形參age
//this指針指向的是被調(diào)用成員函數(shù)所屬的對(duì)象
this->age = age;
}
void PersonAddAge(Person &p)
{
this->age += p.age;
}
//易錯(cuò)點(diǎn)
//Person PersonAddAge2(Person &p)
//error
Person & PersonAddAge2(Person &p)
{
this->age += p.age;
//this是指向p2的指針乡小,而*this就是p2這個(gè)對(duì)象本體
return *this;
}
Person? PersonAddAge3(Person &p)
{
this->age += p.age;
//this是指向p2的指針阔加,而*this就是p2這個(gè)對(duì)象本體
return *this;
}
int age;
};
void test01()
{
Person p1(18);
cout << "the age of p1 is " << p1.age << endl;
}
//2.返回對(duì)象本身用*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;
//鏈?zhǔn)骄幊趟枷?/p>
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的拷貝
? ? ? ? ? ? ? ? ? ? //此時(shí)p2.age=20
cout << "the age of p2 is " << p2.age << endl;
//第一個(gè)函數(shù)更改了p2.age 但返回的是p2的拷貝 記為 p2’
//第二個(gè)函數(shù)更改的是p2’
//第三個(gè)函數(shù)更改的是p2''
//所以p2.age=30
p2.PersonAddAge3(p1).PersonAddAge3(p1).PersonAddAge3(p1);
cout << "the age of p2 is " << p2.age << endl;
}
4.3.3空指針訪問(wèn)成員函數(shù)
C++中空指針也可以調(diào)用成員函數(shù)满钟,但要注意有沒(méi)有用到this指針
如果用到this指針胜榔,需要加以判斷保證代碼健壯性
示例:
class Person
{
public:
//空指針可以正常訪問(wèn)
void showClassName()
{
cout << "this is Person class" << endl;
}
void showPersonAge()
{
//報(bào)錯(cuò)原因是因?yàn)閭魅氲闹羔槥镹ULL
cout << "age is " << m_Age << endl;
//m_Age默認(rèn)為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后我們稱這個(gè)函數(shù)為常函數(shù);
2.常函數(shù)內(nèi)不可以修改成員屬性湃番;
3.成員屬性聲明時(shí)加關(guān)鍵字mutable后夭织,在常函數(shù)中依然可以修改
常對(duì)象:
1.聲明對(duì)象前加const稱該對(duì)象為常對(duì)象;
2.常對(duì)象只能調(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ù)后
//就相當(dāng)于const Person * const this;
? ? //this->m_A = 100;//error
this->m_B = 100;//ok
}
public:
int m_A;
mutable int m_B;//特殊變量泥兰,即使在常函數(shù)中弄屡,也可以修改這個(gè)值
? ? ? ? ? ? ? ? //加關(guān)鍵字mutable
};
void test01()
{
//常對(duì)象
const Person p;
//p.m_A = 100;//error
p.m_B = 100;//ok ,m_B是特殊值,在常對(duì)象下也可以修改
? ? //常對(duì)象只能調(diào)用常函數(shù)
//不可以調(diào)用普通成員函數(shù)鞋诗,因?yàn)槠胀ǔ蓡T函數(shù)可以修改屬性
//p.showPerson1();//error
p.showPerson2();//ok
}
4.4友元
目的:讓一個(gè)函數(shù)或類 訪問(wèn)另一個(gè)類中的私有成員
關(guān)鍵字:friend
友元的三種實(shí)現(xiàn):
1.全局函數(shù)做友元函數(shù)
2.類做友元類
3.類的成員函數(shù)做友元
4.5運(yùn)算符重載
概念:對(duì)已有的運(yùn)算符重新進(jìn)行定義膀捷,賦予其另一種功能,以適應(yīng)不同的數(shù)據(jù)類型
4.5.1加號(hào)運(yùn)算符重載
作用:實(shí)現(xiàn)兩個(gè)自定義數(shù)據(jù)類型相加的運(yùn)算
兩種方式:
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;
}
//運(yùn)算符重載师脂,也可以發(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.對(duì)于內(nèi)置的數(shù)據(jù)類型的表達(dá)式的運(yùn)算符是不可能改變的担孔;
2.不要濫用運(yùn)算符重載;
4.5.2左移運(yùn)算符重載
作用:輸出自定義數(shù)據(jù)類型
注意:只能通過(guò)全局函數(shù)重載輸出流運(yùn)算符吃警,且需要設(shè)置為類的友元函數(shù)
示例:
class Person
{
//將全局函數(shù)設(shè)置為友元
friend ostream & operator<<(ostream &os, Person &p);
public:
//利用成員函數(shù)重載 左移運(yùn)算符 p.operator<<(cout) 簡(jiǎn)化版本 p<<cout
//不會(huì)利用成員函數(shù)重載<<運(yùn)算符 糕篇,因?yàn)闊o(wú)法實(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ù)重載左移運(yùn)算符
//void? operator<<(ostream &cout,Person &p)//本質(zhì) operator<<(cout,p) 簡(jiǎn)化 cout<<p
//{
// cout << "m_A=" << p.m_A << endl
// << "m_B=" << p.m_B << endl;
//}
//ostream 也是一種類
//ostream對(duì)象只能有一個(gè),所以需要加&
ostream & operator<<(ostream &os, Person &p)//本質(zhì) operator<<(cout,p) 簡(jiǎn)化 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時(shí)酌心,上一行程序會(huì)崩掉
//由于左側(cè)返回的是void 拌消,不能實(shí)現(xiàn)鏈?zhǔn)骄幊?/p>
//因此需要對(duì)左移運(yùn)算符重載函數(shù)進(jìn)行返回值的修改
}
總結(jié):重載左移運(yùn)算符配合友元可以實(shí)現(xiàn)輸出自定義數(shù)據(jù)類型