柚子快報(bào)激活碼778899分享:【C++】類(lèi)和對(duì)象(下)
柚子快報(bào)激活碼778899分享:【C++】類(lèi)和對(duì)象(下)
【C++】類(lèi)和對(duì)象(下)
初始化列表構(gòu)造時(shí)的類(lèi)型轉(zhuǎn)化static成員概念特性
友元友元函數(shù)友元類(lèi)
內(nèi)部類(lèi)匿名對(duì)象總結(jié)
初始化列表
在對(duì)類(lèi)和對(duì)象有了基本的認(rèn)識(shí)之后,可以知道在創(chuàng)建對(duì)象的時(shí)候,編譯器通過(guò)調(diào)用構(gòu)造函數(shù),給對(duì)象中各個(gè)成員變量一個(gè)合適的初始值。
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
上面的代碼通過(guò)構(gòu)造函數(shù)賦予了成員變量新的值,但不能稱(chēng)之為對(duì)對(duì)象中成員變量的初始化,構(gòu)造函數(shù)中的語(yǔ)句只能稱(chēng)之為賦初值,而不能稱(chēng)作初始化。
初始化只能初始化一次,而構(gòu)造函數(shù)體內(nèi)可以多次賦值。
初始化列表:以一個(gè)冒號(hào)開(kāi)始,接著是一個(gè)以逗號(hào)分隔的數(shù)據(jù)或成員列表,每個(gè)成員變量后面跟著一個(gè)放在括號(hào)中的初始值或者表達(dá)式。
class Date
{
public:
Date(int year, int month, int day)
//對(duì)象的定義
:_year(year)
,_month(month)
,_day(day)
{}
private:
//對(duì)象的聲明
int _year;
int _month;
int _day;
};
int main(void)
{
Date d(2000,1,1);//對(duì)象的整體定義
return 0;
}
成員變量在類(lèi)里面是聲明,在主函數(shù)(main)中會(huì)對(duì)成員變量進(jìn)行對(duì)象的整體定義,所有C++中規(guī)定了初始化列表,對(duì)象的成員定義的位置便是在初始化列表,在構(gòu)造函數(shù)體內(nèi)進(jìn)行的是成員變量的賦值。
【注意】 1.每一個(gè)成員變量在初始化列表中最多只能出現(xiàn)一次(初始化只能初始化一次)
成員變量可以在初始化列表不出現(xiàn),但是出現(xiàn)最多只能出現(xiàn)一次,否則就會(huì)報(bào)錯(cuò)。
如果成員變量在初始化列表中不出現(xiàn),成員變量中的內(nèi)置類(lèi)型不做處理,而自定義類(lèi)型會(huì)調(diào)用其默認(rèn)的構(gòu)造函數(shù)。
2.類(lèi)中包含以下成員,必須放在初始化列表位置進(jìn)行初始化。
引用成員變量
class B
{
public:
B(int& i)
:_i(i)
{}
private:
int& _i;
};
int main(void)
{
int i = 10;
B b1(i);
return 0;
}
當(dāng)類(lèi)中存在引用成員變量時(shí),必須在定義的時(shí)候初始化。 而在傳引用值時(shí),需要預(yù)先在出函數(shù)中定義好一個(gè)變量,構(gòu)造函數(shù)接收參數(shù)時(shí)使用引用,如果只是傳遞一個(gè)值,在調(diào)用構(gòu)造函數(shù)時(shí)會(huì)建立一個(gè)臨時(shí)變量存儲(chǔ)這個(gè)值,當(dāng)構(gòu)造函數(shù)銷(xiāo)毀時(shí),臨時(shí)變量也會(huì)銷(xiāo)毀,那么此時(shí)這個(gè)引用就會(huì)變成一種野引用。
const成員變量
class B
{
public:
B(int c)
:_c(c)
{}
private:
const int _c;
};
int main(void)
{
B bb1(10);
return 0;
}
當(dāng)類(lèi)中存在const修飾成員變量時(shí),必須在定義的時(shí)候初始化。 被const修飾的變量只有一次初始機(jī)會(huì),此后不可以被修改,所有必須在初始化列表的定義。
自定義類(lèi)型(且該類(lèi)型沒(méi)有默認(rèn)的構(gòu)造函數(shù))
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
class B
{
public:
B(int aa)
:_aa(aa)
{}
private:
A _aa;
};
int main(void)
{
B bb(1);
return 0;
}
當(dāng)自定義類(lèi)型沒(méi)有默認(rèn)構(gòu)造函數(shù)(全缺省、無(wú)參、編譯器自定生成),需要在初始化列表定義,由默認(rèn)構(gòu)造函數(shù),也可以在初始化列表進(jìn)行定義。
有默認(rèn)構(gòu)造函數(shù),默認(rèn)構(gòu)造函數(shù)的參數(shù)為缺省值,需要先考慮初始化列表,初始化列表可以看作是成員變量定義的地方。
【注意】 初始化只是構(gòu)造函數(shù)的一部分,構(gòu)造函數(shù)里面初始化賦值有倆種:第一種是在函數(shù)體內(nèi)賦值,另一種是初始化列表定義。
也就是說(shuō),并不是初始化列表可以滿足構(gòu)造函數(shù)的問(wèn)題,在構(gòu)造函數(shù)內(nèi)部可以進(jìn)行一些其他的工作,例如內(nèi)存的開(kāi)辟,內(nèi)存開(kāi)辟后的判斷,多維數(shù)組的建立等等。
class Stack
{
public:
Stack(int capacity)
:_capacity(capacity)
,_size(0)
{
_a = (int*)malloc(sizeof(int) * capacity);
if (_a == nullptr)
{
perror("malloc fail");
return;
}
}
private:
int* _a;
int _capacity;
int _size;
};
3.盡量使用初始化列表初始化,因?yàn)椴还苣闶欠袷褂贸跏蓟斜?,?duì)于自定義類(lèi)型成員變量,一定會(huì)先使用初始化列表。
4.成員變量在類(lèi)中聲明次序就是其在初始化列表中的初始化順序,與其在初始化列表中的先后順序無(wú)關(guān)。
class A
{
public:
A(int a)
:_a2(a)
,_a1(_a2)
{}
private:
int _a1;
int _a2;
};
這段錯(cuò)誤代碼就演示了在初始化列表中先定義_a1時(shí),使用_a2的值賦給_a1,由于_a2還未定義,所以_a1會(huì)出現(xiàn)隨機(jī)值。
構(gòu)造時(shí)的類(lèi)型轉(zhuǎn)化
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
int main(void)
{
A aa1 = 2;
return 0;
}
對(duì)對(duì)象初始化時(shí),將一個(gè)整數(shù)類(lèi)型賦值給自定義類(lèi)型,這種方式被稱(chēng)為隱式類(lèi)型轉(zhuǎn)換,會(huì)先通過(guò)整數(shù)構(gòu)造一個(gè)自定義類(lèi)型的臨時(shí)變量,臨時(shí)變量在拷貝構(gòu)造給需要構(gòu)造的對(duì)象——>這種過(guò)程直接會(huì)被編譯器有優(yōu)化為直接構(gòu)造,不通過(guò)拷貝構(gòu)造。 在同一個(gè)表達(dá)式中,連續(xù)的構(gòu)造編譯器一般會(huì)優(yōu)化。
這段代碼報(bào)錯(cuò)的原因是,整數(shù)int類(lèi)型在構(gòu)造一個(gè)自定義類(lèi)型的臨時(shí)變量時(shí),由于臨時(shí)變量具有常性,所以在將臨時(shí)變量拷貝給自定義類(lèi)型時(shí),臨時(shí)變量會(huì)釋放,引用會(huì)變成野引用,所以直接使用引用是不可以的。
可以使用const來(lái)使用引用,因?yàn)閏onst引用不能被修改。
使用explicit關(guān)鍵字修飾構(gòu)造函數(shù),將會(huì)禁止構(gòu)造函數(shù)的隱式住轉(zhuǎn)化。
static成員
概念
聲明為static的類(lèi)成員稱(chēng)為類(lèi)的靜態(tài)成員,用static修飾的成員變量稱(chēng)為靜態(tài)成員變量。用static修飾的成員函數(shù)稱(chēng)之為靜態(tài)成員函數(shù)。
靜態(tài)成員變量一定要在類(lèi)外進(jìn)行初始化。
例如:檢查程序中有多少個(gè)對(duì)象正在使用
//使用全局變量
int _count = 0;
class A
{
public:
A(int a)
:_a(a)
{
++_count;
}
A(const A& a)
{
++_count;
}
~A()
{
--_count;
}
private:
int _a;
};
void Fun1()
{
A aa3(2);
cout << __LINE__ << ":" << _count << endl;
}
int main(void)
{
A aa1(1);
cout << __LINE__ << ":" << _count << endl;
A aa2(aa1);
cout << __LINE__ << ":" << _count << endl;
Fun1();
cout << __LINE__ << ":" << _count << endl;
return 0;
}
此代碼使用全局變量來(lái)測(cè)試,但是全局變量的劣勢(shì)是任何地方都可以將其修改。
類(lèi)中除了可以定義成員變量,同時(shí)也可以定義靜態(tài)成員變量。
class A
{
public:
A(int a)
:_a(a)
{
++_count;
}
A(const A& a)
{
++_count;
}
~A()
{
--_count;
}
static int GetCount()
{
return _count;
}
private:
int _a;
static int _count;
};
int A::_count = 0;
void Fun1()
{
A aa3(2);
cout << __LINE__ << ":" << A::GetCount() << endl;
}
int main(void)
{
A aa1(1);
cout << __LINE__ << ":" << A::GetCount() << endl;
A aa2(aa1);
cout << __LINE__ << ":" << A::GetCount() << endl;
Fun1();
cout << __LINE__ << ":" << A::GetCount() << endl;
return 0;
}
對(duì)于成員變量與靜態(tài)成員變量的區(qū)別是,成員變量屬于每一個(gè)類(lèi)對(duì)象,每一個(gè)對(duì)象中都會(huì)有成員變量,而靜態(tài)成員變量只屬于類(lèi),屬于類(lèi)中每一個(gè)類(lèi)對(duì)象共享的變量,存儲(chǔ)在靜態(tài)區(qū),其聲明周期是全局的。
靜態(tài)成員變量只在全局位置,類(lèi)的外面定義,由于靜態(tài)成員變量在類(lèi)中被封裝后變成私有,所以靜態(tài)成員函數(shù)不可以被訪問(wèn),所以可以使用類(lèi)中公共的成員函數(shù)。
class A
{
public:
A(int a)
:_a(a)
{
++_count;
}
A(const A& a)
{
++_count;
}
~A()
{
--_count;
}
int GetCount()
{
return _count;
}
private:
int _a;
static int _count;
};
int A::_count = 0;
void Fun1()
{
A aa3(2);
cout << __LINE__ << ":" << aa3.GetCount() << endl;
}
int main(void)
{
A aa1(1);
cout << __LINE__ << ":" << aa1.GetCount() << endl;
A aa2(aa1);
cout << __LINE__ << ":" << aa1.GetCount() << endl;
Fun1();
cout << __LINE__ << ":" << aa1.GetCount() << endl;
return 0;
}
這種方式是無(wú)法對(duì)沒(méi)有對(duì)象的程序進(jìn)行調(diào)用函數(shù)。
所以也可以使用靜態(tài)成員函數(shù),靜態(tài)成員函數(shù)沒(méi)有this指針,指定類(lèi)域或者訪問(wèn)限定符就可以訪問(wèn)靜態(tài)成員函數(shù),靜態(tài)成員函數(shù)中不能使用非靜態(tài)成員變量,因?yàn)闆](méi)有this指針。
【注意】由于靜態(tài)成員變量無(wú)法進(jìn)入構(gòu)造,所以無(wú)法通過(guò)初始化列表定義,所以在聲明靜態(tài)成員變量時(shí),無(wú)法給缺省值。
鏈接:使用static計(jì)算1+2+3……+n
class Sum
{
public:
Sum()
{
_sum += _num;
++_num;
}
static int GetSum()
{
return _sum;
}
private:
static int _num;
static int _sum;
};
int Sum::_num = 1;
int Sum::_sum = 0;
class Solution {
public:
int Sum_Solution(int n)
{
Sum arr[n];
return Sum::GetSum();
}
};
設(shè)計(jì)一個(gè)類(lèi)只能在棧上創(chuàng)建對(duì)象
class A
{
public:
static A GetStackObj(int a)
{
A a1(a);
return a1;
}
private:
A(int a1)
:_a1(a1)
{}
int _a1;
};
int main(void)
{
A a1 = A::GetStackObj();
return 0;
}
特性
1.靜態(tài)成員為所有類(lèi)對(duì)象所共享,不屬于某個(gè)具體的對(duì)象,存放在靜態(tài)區(qū) 2.靜態(tài)成員變量必須在類(lèi)外面定義,定義時(shí)不添加static關(guān)鍵字,在類(lèi)里面只是聲明 3.類(lèi)靜態(tài)成員即可用 類(lèi)名::靜態(tài)成員 或者 對(duì)象.靜態(tài)成員 來(lái)訪問(wèn) 4.靜態(tài)成員函數(shù)沒(méi)有隱藏的this指針,不能訪問(wèn)任何非靜態(tài)成員 5.靜態(tài)成員也是類(lèi)的成員,受public,protected,privated的影響 6.非靜態(tài)成員函數(shù)可以調(diào)用靜態(tài)成員函數(shù),原因是靜態(tài)成員函數(shù)沒(méi)有this指針,不構(gòu)成影響 7.靜態(tài)成員函數(shù)不能調(diào)用非靜態(tài)成員函數(shù),是因?yàn)榉庆o態(tài)成員函數(shù)調(diào)用需要this指針,而靜態(tài)成員函數(shù)沒(méi)有this指針
友元
友元提供了一種突破封裝的方式,有時(shí)可以利用友元提供方便,但使用友元會(huì)增加耦合度(關(guān)聯(lián)度更加緊密),可能會(huì)破壞封裝。 友元使用關(guān)鍵字friend 友元可以分為:友元函數(shù)與友元類(lèi)。
友元函數(shù)
友元函數(shù)可以直接訪問(wèn)類(lèi)的私有成員,它是定義在類(lèi)外部的普通函數(shù),不屬于任何類(lèi),但需要在類(lèi)的內(nèi)部聲明,聲明時(shí)需要加friend關(guān)鍵字。
以流插入舉例:
class Date
{
friend ostream& operator<<(ostream& out, Date& d);
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, Date& d)
{
out << d._year << "/" << d._month << "/" << d._day;
return out;
}
觀察這段代碼,無(wú)法將operator<<放在類(lèi)中成為重載成員函數(shù),是因?yàn)閏out的輸出流對(duì)象和隱含的this指針在搶占第一個(gè)參數(shù)的位置,this指針默認(rèn)是第一個(gè)參數(shù),也就是左操作數(shù)。
d << cout;
但是實(shí)際使用中cout需要是第一個(gè)形參對(duì)象,才能正常使用,可以將operator重載成全局函數(shù),但是此時(shí)又會(huì)導(dǎo)致類(lèi)外沒(méi)辦法訪問(wèn)成員,此時(shí)就需要友元來(lái)解決。
【注意】 1.友元函數(shù)可以訪問(wèn)類(lèi)的私有和保護(hù)成員,但是不是類(lèi)的成員函數(shù) 2.友元函數(shù)不能使用const修飾 3.友元函數(shù)可以哎類(lèi)定義的任何地方聲明,不受類(lèi)訪問(wèn)限定符限制 4.一個(gè)函數(shù)可以是多個(gè)類(lèi)的友元函數(shù) 5.友元函數(shù)的調(diào)用與普通的調(diào)用原理相同
友元類(lèi)
class Date
{
friend class Time;
public:
Date(int year = 2000, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
class Time
{
public:
Time(int hour, int minute, int second)
:_hour(hour)
,_minute(minute)
,_second(second)
{}
void Print()
{
cout << _d._year << " " << _d._month << " " << _d._day << " "
<< _hour << " " << _minute << " " << _second;
}
private:
int _hour;
int _minute;
int _second;
Date _d;
};
int main(void)
{
Time T1(2, 23, 15);
T1.Print();
return 0;
}
友元類(lèi)的所有成員函數(shù)都可以是另一個(gè)類(lèi)的友元函數(shù),都可以訪問(wèn)另一個(gè)類(lèi)中的非公有成員。
友元函數(shù)是單向的,不具有交換性。友元關(guān)系不能傳遞。 例如:如果C是B的友元,B是A的友元,則不能說(shuō)明C是A的友元。友元關(guān)系不能繼承。
內(nèi)部類(lèi)
概念·:如果一個(gè)類(lèi)定義在另一個(gè)類(lèi)的內(nèi)部,這個(gè)內(nèi)部類(lèi)就叫做內(nèi)部類(lèi)。內(nèi)部類(lèi)是一個(gè)獨(dú)立的類(lèi),它不屬于外部類(lèi),更不能通過(guò)外部類(lèi)的對(duì)象去訪問(wèn)內(nèi)部類(lèi)的成員。外部類(lèi)對(duì)內(nèi)部類(lèi)沒(méi)有任何優(yōu)越的訪問(wèn)權(quán)限。
【特性】 1.內(nèi)部類(lèi)可以定義在外部類(lèi)的public、protected、private都是可以的,其效果不同。 2.注意內(nèi)部類(lèi)可以直接訪問(wèn)外部類(lèi)中的static成員,不需要外部類(lèi)的對(duì)象或者類(lèi)名 3.sizeof(外部類(lèi))==外部類(lèi),和內(nèi)部類(lèi)沒(méi)有任何關(guān)系。 4.sizeof(類(lèi))時(shí),里面的靜態(tài)變量不計(jì)算,是因?yàn)殪o態(tài)變量沒(méi)有存儲(chǔ)在對(duì)象里面。 5.內(nèi)部類(lèi)天生是外部類(lèi)的友元。
class A
{
public:
class B
{
public:
B()
:_b(2)
{}
void Print(const A& a)
{
cout << a._a << _b << endl;
}
private:
int _b;
};
A()
:_a(1)
{}
private:
int _a;
};
int main()
{
A a;
A::B b;
b.Print(a);
return 0;
}
【注意】 內(nèi)部類(lèi)就是外部類(lèi)的友元類(lèi),同友元類(lèi)一樣,內(nèi)部類(lèi)可以通過(guò)外部類(lèi)的對(duì)象參數(shù)來(lái)訪問(wèn)外部類(lèi)中的所有成員,但外部類(lèi)不是內(nèi)部類(lèi)的友元。
匿名對(duì)象
有名對(duì)象
A aa1(1);
匿名對(duì)象
A(2);
有名對(duì)象調(diào)用調(diào)用函數(shù)
Date d1;
d1.Print();
匿名函數(shù)調(diào)用對(duì)象
Date().Print();
有名對(duì)象的生命周期在當(dāng)前函數(shù)局部域,匿名對(duì)象的生命周期在當(dāng)前行。
匿名對(duì)象與有名對(duì)象的區(qū)別僅僅是匿名無(wú)名,而有名有名。
匿名對(duì)象與臨時(shí)對(duì)象相似,具有常性。
//錯(cuò)誤代碼
A& a1 = A(1);
//正確代碼
const A& a2 = A(1);
const引用延長(zhǎng)了匿名對(duì)象的生命周期,生命周期在當(dāng)前函數(shù)局部域。
同時(shí),同一行一個(gè)表達(dá)式中連續(xù)的構(gòu)造+拷貝構(gòu)造會(huì)進(jìn)行優(yōu)化。
總結(jié)
在類(lèi)和對(duì)象階段,需要體會(huì)到,類(lèi)是對(duì)某一類(lèi)實(shí)體(對(duì)象)來(lái)進(jìn)行描述的,描述該對(duì)象具有哪些屬性,哪些方法,描述完成后就形成了一種新的自定義類(lèi)型,才有該自定義類(lèi)型就可以實(shí)例化具體的對(duì)象。
柚子快報(bào)激活碼778899分享:【C++】類(lèi)和對(duì)象(下)
好文推薦
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。