1? 類型轉(zhuǎn)換構(gòu)造函數(shù)
1.1? why?
? ? ? ? 基本類型之間的轉(zhuǎn)換,編譯器內(nèi)置轉(zhuǎn)換規(guī)則:int -> double
? ? ? ? 類類型之間的轉(zhuǎn)換,編譯器不知道轉(zhuǎn)換規(guī)則,需要用戶提供:Cat -> Dog
// consconv_why.cpp 為什么需要自定義轉(zhuǎn)換
#include <iostream>
using namespace std;
class Cat {
public:
Cat( const char* name ) : m_name(name) {
//【string m_name(name);】
}
void talk( ) {
cout << m_name << ": 喵喵~~~" << endl;
}
private:
string m_name;
};
class Dog {
public:
Dog( const char* name ) : m_name(name) {
//【string m_name(name);】
}
void talk( ) {
cout << m_name << ": 汪汪~(yú)~~" << endl;
}
private:
string m_name;
};
// 模擬類的設(shè)計(jì)者(類庫(kù)、別人設(shè)計(jì)的類、自己設(shè)計(jì)的類)
// --------------------------------
// 模擬用戶(使用類的人)
int main( void ) {
Cat smallwhite("小白");
smallwhite.talk( );
Dog bigyellow = smallwhite; // Cat --> Dog
return 0;
}
1.2? 理論
? ? ? ? 定義:1)單參構(gòu)造? ? ? ? ? ? ? ? ? ? ? ? ? ? (同于拷貝構(gòu)造函數(shù))? ?
? ? ? ? ? ? ? ? ? ?2)參數(shù)類型與類類型不同? ? ? (異于拷貝構(gòu)造函數(shù))
? ? ? ? (單參構(gòu)造就2種,參數(shù)類型同于類類型,就是拷貝構(gòu)造,否則就是類型轉(zhuǎn)換構(gòu)造)
? ? ? ? class? ?目標(biāo)類型 {
? ? ? ? ? ? ? ? ? ?目標(biāo)類型 ( const? 源類型&? src ) { ... }? // 類型轉(zhuǎn)換構(gòu)造函數(shù)
? ? ? ? ? ? ? ? ? ? };
? ? ? ? 用于:
? ? ? ? 1)利用一個(gè)已定義的對(duì)象,來(lái)定義另一個(gè)不同類型的對(duì)象
? ? ? ? 2)實(shí)現(xiàn)從源類型到目標(biāo)類型的隱式類型轉(zhuǎn)換?
? ? ? ? 通過(guò)explicit關(guān)鍵字,可以強(qiáng)制? 這種通過(guò)類型轉(zhuǎn)換構(gòu)造函數(shù)實(shí)現(xiàn)的類型轉(zhuǎn)換? 必須通過(guò)靜態(tài)轉(zhuǎn)換顯示地進(jìn)行:
? ? ? ? class? 目標(biāo)類型 {
? ? ? ? ? ? ? ? explicit? 目標(biāo)類型 ( const? 源類型&? src ) { ... };
? ? ? ? };
// consconv.cpp
// 類型轉(zhuǎn)換構(gòu)造函數(shù) -- 指定 源類型 到 目標(biāo)類型 的 轉(zhuǎn)換規(guī)則
#include <iostream>
using namespace std;
class Cat {
public:
explicit Cat( const char* name ) : m_name(name) { // 類型轉(zhuǎn)換構(gòu)造函數(shù)
//【string m_name(name);】
cout << "Cat類的類型轉(zhuǎn)換構(gòu)造函數(shù)被調(diào)用" << endl;
}
void talk( ) {
cout << m_name << ": 喵喵~~~" << endl;
}
private:
string m_name;
friend class Dog; // 友元聲明
};
class Dog {
public:
Dog( const char* name ) : m_name(name) { // 類型轉(zhuǎn)換構(gòu)造函數(shù)
//【string m_name(name);】
}
explicit Dog( const Cat& c ) : m_name(c.m_name) { // 類型轉(zhuǎn)換構(gòu)造函數(shù)(Cat-->Dog的轉(zhuǎn)換規(guī)則)
//【string m_name=c.m_name;】
cout << "Dog類的類型轉(zhuǎn)換構(gòu)造函數(shù)被調(diào)用" << endl;
}
void talk( ) {
cout << m_name << ": 汪汪~(yú)~~" << endl;
}
private:
string m_name;
};
// 模擬類的設(shè)計(jì)者(類庫(kù)、別人設(shè)計(jì)的類、自己設(shè)計(jì)的類)
// --------------------------------
// 模擬用戶(使用類的人)
int main( void ) {
// Cat smallwhite("小白"); // 定義smallwhite,利用smallwhite.Cat("小白")->類型轉(zhuǎn)換構(gòu)造函數(shù)
// Cat smallwhite = "小白"; // 定義 匿名Cat類對(duì)象,利用 匿名Cat類對(duì)象.Cat("小白")->隱式轉(zhuǎn)換
// Cat smallwhite=匿名Cat類對(duì)象-->克隆
Cat smallwhite = static_cast<Cat>("小白");
// 定義 匿名Cat類對(duì)象,利用 匿名Cat類對(duì)象.Cat("小白")->靜態(tài)轉(zhuǎn)換
// Cat smallwhite=匿名Cat類對(duì)象-->克隆
smallwhite.talk( );
// Dog bigyellow(smallwhite); // 定義bigyellow,利用bigyellow.Dog(smallwhite)->類型轉(zhuǎn)換構(gòu)造函數(shù)
// Dog bigyellow = smallwhite; // 定義 匿名Dog類對(duì)象,利用 匿名Dog類對(duì)象.Dog(smallwhite)->隱式類型轉(zhuǎn)換
// Dog bigyellow = 匿名Dog類對(duì)象-->克隆
Dog bigyellow = static_cast<Dog>(smallwhite);
// 定義 匿名Dog類對(duì)象,利用 匿名Dog類對(duì)象.Dog(smallwhite)->靜態(tài)類型轉(zhuǎn)換
// Dog bigyellow = 匿名Dog類對(duì)象-->克隆
bigyellow.talk( );
return 0;
}
2? 析構(gòu)函數(shù)
2.1? 理論
????????析構(gòu)函數(shù)的函數(shù)名就是在類名前面加“~”,沒(méi)有返回類型也沒(méi)有參數(shù),不能重載。
? ? ? ? 在銷毀對(duì)象之前一刻自動(dòng)被調(diào)用,且僅被調(diào)用一次?:
? ? ? ? ? ? ? ? - 對(duì)象離開(kāi)作用域? ?(棧對(duì)象離開(kāi)main函數(shù))
? ? ? ? ? ? ? ? - delete操作符? ? ? ? (堆對(duì)象被釋放)
? ? ? ? 作用:銷毀? 對(duì)象的各個(gè)成員變量?
? ? ? ? 如果一個(gè)類沒(méi)有定義析構(gòu)函數(shù),那么編譯器會(huì)為其提供一個(gè)默認(rèn)的析構(gòu)函數(shù):
? ? ? ? ? ? ? ? - 對(duì)基本類型的成員變量,什么也不做。
? ? ? ? ? ? ? ? - 對(duì)類類型的成員變量,調(diào)用相應(yīng)類型的析構(gòu)函數(shù)。
? ? ? ? ? ? ? ? - 銷毀 對(duì)象的各個(gè)成員變量?
2.2? 析構(gòu)過(guò)程
????????
? ? ? ? 對(duì)象的銷毀過(guò)程:
????????1)調(diào)用析構(gòu)函數(shù)(陷)
? ? ? ? ? ? ? ? - 執(zhí)行自己在析構(gòu)函數(shù)中書(shū)寫(xiě)的代碼?
? ? ? ? ? ? ? ? - 利用類成員變量調(diào)用相應(yīng)的析構(gòu)函數(shù)?
? ? ? ? ? ? ? ? - 釋放對(duì)象的各成員變量所占內(nèi)存空間?
? ? ? ? 2)釋放整個(gè)對(duì)象所占用的內(nèi)存空間 (皮)
// 析構(gòu)函數(shù)
#include <iostream>
using namespace std;
class Human {
public:
// 如果類沒(méi)有提供任何構(gòu)造函數(shù),編譯器將提供一個(gè)無(wú)參的構(gòu)造函數(shù)
/* Human() {
【int m_age;】定義m_age,初值為隨機(jī)數(shù)
【string m_name;】定義m_name,利用m_name.string()
}*/
Human( int age=0, const char* name="無(wú)名" ) : m_age(age),m_name(name) {
//【int m_age=age;】定義m_age,初值為age
//【string m_name(name);】定義m_name,利用m_name.string(name)
cout << "Human類缺省構(gòu)造函數(shù)被調(diào)用" << endl;
}
// 如果類沒(méi)有提供拷貝構(gòu)造函數(shù),編譯器將提供一個(gè)默認(rèn)的拷貝構(gòu)造函數(shù)
/* Human( const Human& that ) {
【int m_age=that.m_age;】定義m_age,初值為that.m_age
【string m_name(that.m_name);】定義m_name,利用m_name.string(that.m_name)-->string類拷貝構(gòu)造函數(shù)
}*/
Human( const Human& that ) : m_age(that.m_age), m_name(that.m_name) {
//【int m_age=that.m_age;】定義m_age,初值為that.m_age
//【string m_name(that.m_name);】定義m_name,利用m_name.string(that.m_name)
cout << "Human類拷貝構(gòu)造函數(shù)被調(diào)用" << endl;
}
// 如果類沒(méi)有提供拷貝賦值函數(shù),編譯器將提供一個(gè)默認(rèn)的拷貝賦值函數(shù)
/* Human& operator=( const Human& that ) {
this->m_age = that.m_age;
this->m_name = that.m_name; // this->m_name.operator=(that.m_name)-->string類的拷貝賦值函數(shù)
return *this;
}*/
Human& operator=( const Human& that ) {
// 編譯器不會(huì)再拷貝賦值函數(shù)中塞任何操作
cout << "Human類的拷貝賦值函數(shù)被調(diào)用" << endl;
this->m_age = that.m_age;
this->m_name = that.m_name; // this->m_name.operator=(that.m_name)-->string類的拷貝賦值函數(shù)
return *this;
}
// 如果類沒(méi)有提供析構(gòu)函數(shù),編譯器將提供一個(gè)默認(rèn)的析構(gòu)函數(shù)
/* ~Human() {
對(duì)于基本類型成員變量m_age,什么都不做
對(duì)于類類型成員變量m_name,利用 m_name.~string()
釋放 m_age/m_name 本身所占內(nèi)存空間
}*/
~Human() {
cout << "Human類的析構(gòu)函數(shù)被調(diào)用" << endl;
// 對(duì)于基本類型成員變量m_age,什么都不做
// 對(duì)于類類型成員變量m_name,利用 m_name.~string()
// 釋放 m_age/m_name 本身所占內(nèi)存空間
}
void getinfo( ) {
cout << "姓名: " << m_name << ", 年齡: " << m_age << endl;
}
private:
int m_age; // 基本類型的成員變量
string m_name; // 類類型的成員變量
};
// 模擬類的設(shè)計(jì)者(類庫(kù)、別人設(shè)計(jì)的類、自己設(shè)計(jì)的類)
// --------------------------------
// 模擬用戶(使用類的人)
int main( void ) {
Human h; // 定義h,利用h.Human()-->h維護(hù)的內(nèi)容為(無(wú)名,0)
h.getinfo( );
Human h2(22,"張飛"); // 定義h2,利用h2.Human(22,"張飛")-->h2維護(hù)的內(nèi)容為(張飛,22)
h2.getinfo();
Human h3(h2); // = h2; // 定義h3,利用h3.Human(h2)-->觸發(fā)拷貝構(gòu)造函數(shù)
h3.getinfo();
Human h4; // 定義h4,利用h4.Human()-->h4維護(hù)的內(nèi)容為(無(wú)名,0)
cout << "h4被賦值前---";
h4.getinfo();
h4 = h3; // h4.operator=(h3)-->觸發(fā)拷貝賦值函數(shù)
cout << "h4被賦值后---";
h4.getinfo();
cout << "------------main will be over----------------" << endl;
return 0;
} //(1) h.~Human() h2.~Human() h3.~Human() h4.~Human() (2)釋放h/h2/h3/h4本身所占的內(nèi)存空間
//(1) 刪餡 (2)刪皮
2.3? has to
? ? ? ? 通常情況下,若對(duì)象在其聲明周期的最終時(shí)刻,并不持有任何動(dòng)態(tài)分配的資源,可以不定義析構(gòu)函數(shù)。
? ? ? ? 若對(duì)象在其聲明周期的最終時(shí)刻,持有動(dòng)態(tài)資源,則必須定義析構(gòu)函數(shù),釋放對(duì)象所持有的動(dòng)態(tài)資源。
// hastodes必須自己寫(xiě)析構(gòu)函數(shù)的情況 -- 對(duì)象臨死時(shí),持有動(dòng)態(tài)資源
#include <iostream>
using namespace std;
class A {
public:
A(int i) : m_i(i), m_p(new int), m_f(open("./file", O_CREAT|O_RDWR,0644)) {
//【int m_i=i;】定義m_i,初值為i
//【int* m_p=new int;】定義m_p,初值為指向一塊堆內(nèi)存(動(dòng)態(tài)資源)
//【int m_f=open(...);】定義m_f,初值為文件描述符-->文件表等內(nèi)核結(jié)構(gòu)(動(dòng)態(tài)資源)
}
~A() {
delete m_p;
close( m_f ); // 動(dòng)態(tài)資源需要自己寫(xiě)代碼釋放
// 釋放m_i / m_p / m_f 本身所占內(nèi)存空間
}
/* 默認(rèn)析構(gòu)函數(shù)
~A() {
釋放m_i / m_p / m_f 本身所占內(nèi)存空間
}
*/
private:
int m_i;
int* m_p;
int m_f;
};
// 模擬類的設(shè)計(jì)者(類庫(kù)、別人設(shè)計(jì)的類、自己設(shè)計(jì)的類)
// --------------------------------
// 模擬用戶(使用類的人)
int main( void ) {
A a; // 定義a,利用a.A()
return 0;
} // a.~A() 釋放a本身所占內(nèi)存空間
? ? ? ? 析構(gòu)函數(shù)的功能并不局限在釋放資源上,它還可以執(zhí)行? 我們希望在? 對(duì)象被釋放之前? 執(zhí)行的任何操作。?
3? 深拷貝
3.1? 淺拷貝缺陷
? ? ? ? 如果類不提供拷貝構(gòu)造,編譯器將提供默認(rèn)的拷貝構(gòu)造。
? ? ? ? 無(wú)論是??拷貝構(gòu)造??還是??拷貝賦值,其默認(rèn)實(shí)現(xiàn),對(duì)任何類型的指針成員都是簡(jiǎn)單地復(fù)制地址,而并不復(fù)制地址指向的數(shù)據(jù),這種情況稱為淺拷貝。(左圖)
? ? ? ? 為了獲得完整意義上的對(duì)象副本,必須自己定義??拷貝構(gòu)造? 和? 拷貝賦值,針對(duì)指針型成員變量做深拷貝。(右圖)
???????????
// copybytes_pre.cpp 類中有指針成員,默認(rèn)拷貝構(gòu)造 會(huì)有淺拷貝缺陷
#include <iostream>
#include <cstring>
using namespace std;
// 模擬C++標(biāo)準(zhǔn)的string類 實(shí)現(xiàn)自己的String類
class String {
public:
String( const char* psz="" ) : m_psz(new char[strlen(psz)+1]) {
//【char* m_psz=new char[strlen(psz)+1];】// 動(dòng)態(tài)資源
strcpy( m_psz, psz );
}
~String( /* String* this */ ) {
delete[] this->m_psz;
// 釋放 m_psz 本身所占內(nèi)存空間
}
char* c_str() { return m_psz; }
// 默認(rèn)的拷貝構(gòu)造
/* String( const String& that ) {
【char* m_psz = that.m_psz;】只復(fù)制了地址,沒(méi)有復(fù)制地址指向的數(shù)據(jù)-->淺拷貝
}*/
private:
char* m_psz;
};
// 模擬類的設(shè)計(jì)者(類庫(kù)、別人設(shè)計(jì)的類、自己設(shè)計(jì)的類)
// --------------------------------
// 模擬用戶(使用類的人)
int main( void ) {
String s1("hello");
cout << "s1:" << s1.c_str() << ", s1中的m_psz指向的堆內(nèi)存的地址: " << (void*)s1.c_str() << endl;
String s2(s1); // = s1; 定義s2,利用s2.String(s1)-->拷貝構(gòu)造函數(shù)
cout << "s2:" << s2.c_str() << ", s2中的m_psz指向的堆內(nèi)存的地址: " << (void*)s2.c_str() << endl;
return 0;
} // s1.~String() s2.~String()
????????相對(duì)于拷貝構(gòu)造,拷貝賦值需要做更多的工作:
? ? ? ? ? ? ? ? - 避免自賦值
? ? ? ? ? ? ? ? - 分配新資源
? ? ? ? ? ? ? ? - 拷貝新內(nèi)容
? ? ? ? ? ? ? ? - 釋放舊資源
? ? ? ? ? ? ? ? - 返回自引用
// copybytes.cpp 類中有指針成員,默認(rèn)拷貝構(gòu)造 會(huì)有淺拷貝缺陷
#include <iostream>
#include <cstring>
using namespace std;
// 模擬C++標(biāo)準(zhǔn)的string類 實(shí)現(xiàn)自己的String類
class String {
public:
String( const char* psz="" ) : m_psz(new char[strlen(psz)+1]) {
//【char* m_psz=new char[strlen(psz)+1];】// 動(dòng)態(tài)資源
strcpy( m_psz, psz );
}
~String( /* String* this */ ) {
delete[] this->m_psz;
// 釋放 m_psz 本身所占內(nèi)存空間
}
char* c_str() { return m_psz; }
// 默認(rèn)的拷貝構(gòu)造
/* String( const String& that ) {
【char* m_psz = that.m_psz;】只復(fù)制了地址,沒(méi)有復(fù)制地址指向的數(shù)據(jù)-->淺拷貝
}*/
// 深拷貝構(gòu)造函數(shù)
String( const String& that ) : m_psz(new char[strlen(that.m_psz)+1]) {
//【char* m_psz = new char[strlen(that.m_psz)+1];】
strcpy( m_psz, that.m_psz ); // 不復(fù)制地址,復(fù)制地址指向的數(shù)據(jù)-->深拷貝
}
/* 默認(rèn)拷貝賦值函數(shù)
String& operator=( const String& that ) {
this->m_psz = that.m_psz; // 只復(fù)制了地址,沒(méi)有復(fù)制地址指向的數(shù)據(jù)-->淺拷貝
return *this;
}
*/
// 深拷貝賦值函數(shù)
String& operator=( const String& that ) {
if( this != &that ) { // 防止自賦值
delete[] this->m_psz; // 釋放舊資源
this->m_psz = new char[strlen(that.m_psz)+1]; // 分配新資源
strcpy( this->m_psz, that.m_psz ); // 拷貝新內(nèi)容
}
return *this; // 返回自引用
}
private:
char* m_psz;
};
// 模擬類的設(shè)計(jì)者(類庫(kù)、別人設(shè)計(jì)的類、自己設(shè)計(jì)的類)
// --------------------------------
// 模擬用戶(使用類的人)
int main( void ) {
String s1("hello");
cout << "s1:" << s1.c_str() << ", s1中的m_psz指向的堆內(nèi)存的地址: " << (void*)s1.c_str() << endl;
String s2(s1); // = s1; 定義s2,利用s2.String(s1)-->拷貝構(gòu)造函數(shù)
cout << "s2:" << s2.c_str() << ", s2中的m_psz指向的堆內(nèi)存的地址: " << (void*)s2.c_str() << endl;
String s3; // 定義s3,利用s3.String()-->s3維護(hù)一個(gè)字節(jié)堆內(nèi)存('\0')
s3 = s2; // s3.operator=(s2)
cout << "s3:" << s3.c_str() << ", s3中的m_psz指向的堆內(nèi)存的地址: " << (void*)s3.c_str() << endl;
return 0;
} // s1.~String() s2.~String()
3.2? 建議
? ? ? ? 1)只有類中有指針型成員變量,才會(huì)涉及深淺拷貝的問(wèn)題,因此應(yīng)盡量避免使用指針型成員變量。
? ? ? ? 2)如果確實(shí)無(wú)法實(shí)現(xiàn)完整意義上的? 深拷貝拷貝構(gòu)造? 和? 深拷貝拷貝賦值,可將它們私有化,禁止用戶使用。
4? 靜態(tài)成員
4.1? 靜態(tài)成員變量
? ? ? ? 靜態(tài)成員變量? 不屬于對(duì)象? 而? 屬于類:
? ? ? ? ? ? ? ? - 靜態(tài)成員變量不包含在對(duì)象中,進(jìn)程級(jí)生命期
? ? ? ? ? ? ? ? - 靜態(tài)成員變量的定義和初始化,只能在類的外部(即全局域)而不能在構(gòu)造函數(shù)中進(jìn)行。
? ? ? ? ? ? ? ? - 靜態(tài)成員變量依然受? 類作用域? 和? 訪問(wèn)控制限定符? 的約束。
? ? ? ? ? ? ? ? - 訪問(wèn)靜態(tài)成員變量,既可以通過(guò)? 類? 也可以通過(guò)? 對(duì)象。
? ? ? ? ? ? ? ? - 靜態(tài)成員變量為該類的所有對(duì)象實(shí)例所共享。
// static.cpp 類的靜態(tài)成員變量
#include <iostream>
using namespace std;
// 普通成員變量:屬于對(duì)象,對(duì)象的生命期 靜態(tài)成員變量:不屬于對(duì)象,進(jìn)程級(jí)生命期
class A {
public:
A() {
//【int m_i;】
}
int m_i; // 聲明
static int m_si; // 聲明
};
int A::m_si = 0; // 全局域中定義-->進(jìn)程級(jí)生命期
// 模擬類的設(shè)計(jì)者(類庫(kù)、別人設(shè)計(jì)的類、自己設(shè)計(jì)的類)
// --------------------------------
// 模擬用戶(使用類的人)
int main( void ) {
A a, b; // 靜態(tài)成員變量沒(méi)有保存在對(duì)象內(nèi)部-->不屬于對(duì)象
cout << "a對(duì)象的大小:" << sizeof(a) << endl; // 4
cout << "b對(duì)象的大小:" << sizeof(b) << endl; // 4
A::m_si = 888; // 靜態(tài)成員受到類作用域的約束 也受到訪問(wèn)控制限定符的約束-->屬于類
a.m_si = 999; // A::m_si=999;
cout << "b.m_si=" << b.m_si << endl; // A::m_si
// 類的靜態(tài)成員變量,被該類的所有對(duì)象共享
return 0;
}
4.2? 靜態(tài)成員函數(shù)
? ? ? ? 靜態(tài)成員函數(shù)? 不屬于對(duì)象(普通成員函數(shù)也不屬于對(duì)象,更準(zhǔn)確地說(shuō),不用非要對(duì)象來(lái)調(diào))? 而? 屬于類:
? ? ? ? ? ? ? ? - 靜態(tài)成員函數(shù)沒(méi)有this指針,也沒(méi)有常屬性??
? ? ? ? ? ? ? ? - 靜態(tài)成員函數(shù)依然受? 類作用域? 和? 訪問(wèn)控制限定符的約束
? ? ? ? ? ? ? ? - 訪問(wèn)靜態(tài)成員函數(shù),既可以通過(guò)? 類? 也可以通過(guò)? 對(duì)象。(普通成員函數(shù),只對(duì)象)
? ? ? ? ? ? ? ? -靜態(tài)成員函數(shù)只能訪問(wèn)靜態(tài)成員,而非靜態(tài)成員函數(shù)可以訪問(wèn)所有成員。
// static.cpp 類的 靜態(tài)成員變量 和 靜態(tài)成員函數(shù)
#include <iostream>
using namespace std;
// 普通成員函數(shù):必須利用對(duì)象來(lái)調(diào)用 靜態(tài)成員函數(shù):不是必須利用對(duì)象來(lái)調(diào)用
class A {
public:
int m_i; // 普通成員變量
void foo( /* const A* this */ ) const { // 普通成員函數(shù)
cout << "foo is invoked" << endl;
cout << m_i << endl; // ok
cout << m_si << endl;// ok
bar(); // ok
// 以上三行代碼證明 非靜態(tài)成員函數(shù) 即可訪問(wèn)非靜態(tài)成員 也可訪問(wèn) 靜態(tài)成員(不挑食)
}
static int m_si; //靜態(tài)成員變量
static void bar( /*無(wú)this指針*/ ) /*const*/ { // 靜態(tài)成員函數(shù)
cout << "bar is invoked" << endl;
cout << m_si << endl; // ok
// cout << m_i << endl; // error
// foo(); // error
// 以上三行代碼證明 靜態(tài)成員函數(shù) 只能訪問(wèn) 靜態(tài)成員,不能訪問(wèn)非靜態(tài)的普通成員(挑食)
}
};
int A::m_si = 0; // 全局域中定義-->進(jìn)程級(jí)生命期
// 模擬類的設(shè)計(jì)者(類庫(kù)、別人設(shè)計(jì)的類、自己設(shè)計(jì)的類)
// --------------------------------
// 模擬用戶(使用類的人)
int main( void ) {
A a, b;
a.foo(); // foo(&a);
b.foo(); // foo(&b);
A::bar(); // 受到類作用域的約束 也受到訪問(wèn)控制限定符的約束-->屬于類
a.bar(); // A::bar();
b.bar(); // A::bar();
return 0;
}
4.3? 總結(jié)
????????????????????????????????????????????????
? ? ? ? 事實(shí)上,類的靜態(tài)成員變量和靜態(tài)成員函數(shù),更像是普通的全局變量和全局函數(shù),
????????只是多了一層類作用域和訪問(wèn)控制限定符的約束,
????????相當(dāng)于? 具有成員訪問(wèn)屬性的全局變量和全局函數(shù)。
5? 類? 擴(kuò)充
? ? ? ? 空類對(duì)象的大小是1個(gè)字節(jié)。
? ? ? ? 類中不能包含? 本類對(duì)象? 作為? 普通成員變量;
? ? ? ? 類中可以包含? 本類對(duì)象? 作為? 靜態(tài)成員變量。
// class_add
#include <iostream>
using namespace std;
/*
class A { // 空類
};
int main( void ) {
A a; // 空類對(duì)象占1個(gè)字節(jié)內(nèi)存(1個(gè)字節(jié)的垃圾數(shù)據(jù))
A& ra = a;
cout << "空類對(duì)象a的大小: " << sizeof(a) << endl;
return 0;
}
*/
class A {
public:
int m_i;
// A m_a; // error
static A m_sa; // ok
};
int main( void ) {
A a; // 定義a(給a分配內(nèi)存空間)
cout << "對(duì)象a的大小: " << sizeof(a) << endl;
return 0;
}
6? 單例模式
? ? ? ? 要求:設(shè)計(jì)一個(gè)類,要求用戶在使用這個(gè)類時(shí)僅有一個(gè)實(shí)例(只能出現(xiàn)一個(gè)對(duì)象):
? ? ? ? class? Singleton {
? ? ? ? ? ? ? ? // 設(shè)計(jì)這個(gè)類
? ? ? ? };
? ? ? ? int? main(void) {
? ? ? ? ? ? ? ? // 用戶這里只能出現(xiàn)一個(gè)Singleton類對(duì)象,不能出現(xiàn)第二個(gè)
? ? ? ? ? ? ? ? return? 0;
? ? ? ? }
????????
? ? ? ? 實(shí)現(xiàn)方法:
? ? ? ? 1)將? 包括類的拷貝構(gòu)造函數(shù)在內(nèi)的所有構(gòu)造函數(shù) 私有化,防止user在類的外部創(chuàng)建對(duì)象。
? ? ? ? 2)唯一的對(duì)象由類的設(shè)計(jì)者來(lái)創(chuàng)建
? ? ? ? 3)提供公有靜態(tài)成員函數(shù)getInstance()使用戶可以獲取到唯一對(duì)象。
? ? ? ? 單例分類:
? ? ? ? 1)餓漢式:無(wú)論用不用,程序啟動(dòng)即創(chuàng)建? hungry.cpp (不推薦)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-770863.html
? ? ? ? 2)懶漢式:用的時(shí)候創(chuàng)建,不用了即銷毀? lazy.cpp? (推薦)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-770863.html
// hungry_singleton.cpp
// 單例模式--要求設(shè)計(jì)一個(gè)類型,用戶在使用這個(gè)類時(shí)只能出現(xiàn)一個(gè)對(duì)象
#include <iostream>
using namespace std;
// 餓漢式單例
class Singleton {
public://4 //5
static Singleton& getInstance( ) {
return s_instance;
}
private:
Singleton( ) {} // 1
Singleton( const Singleton& that ) {} // 6
static Singleton s_instance; // 2 唯一對(duì)象
};
Singleton Singleton::s_instance; // 3
// 以上代碼模擬類的設(shè)計(jì)者
// -----------------------
// 以下代碼模擬類的使用者
int main( void ) {
Singleton& s1 = Singleton::getInstance( );
Singleton& s2 = Singleton::getInstance( );
Singleton& s3 = Singleton::getInstance( );
cout << "&s1: " << &s1 << ", &s2: " << &s2 << ", &s3: " << &s3 << endl;
return 0;
}
// lazy_singleton.cpp
// 單例模式:設(shè)計(jì)一個(gè)類,保證用戶在使用這個(gè)類時(shí),只能出現(xiàn)一個(gè)對(duì)象
#include <iostream>
using namespace std;
// 懶漢式單例:單例高級(jí)實(shí)現(xiàn)手法
class Singleton {
public:
static Singleton& getInstance( ) {
if( s_instance==NULL ) {
s_instance = new Singleton; // 唯一的對(duì)象
cout << "創(chuàng)建了唯一的對(duì)象" << endl;
}
++s_counter;
return *s_instance;
}
void releaseInstance( ) {
if( --s_counter == 0 ) {
delete s_instance;
s_instance = NULL;
cout << "銷毀了唯一的對(duì)象" << endl;
}
}
private:
Singleton() {}
Singleton( const Singleton& that ) {}
static Singleton* s_instance; // 并不是唯一對(duì)象,僅僅是一個(gè)指針而已
static int s_counter; // 計(jì)數(shù)功能
};
Singleton* Singleton::s_instance = NULL; // 程序剛剛時(shí),唯一的對(duì)象不存在
int Singleton::s_counter = 0;
// 以上的代碼模擬類的設(shè)計(jì)者(例如:類庫(kù)、被人設(shè)計(jì)的類、自己的設(shè)計(jì)的類)
// -------------------------------------
// 以下的代碼模擬用戶(使用類的人)
int main( void ) {
Singleton& s1 = Singleton::getInstance(); // 第一次調(diào)用getInstance函數(shù)時(shí),創(chuàng)建唯一的對(duì)象
Singleton& s2 = Singleton::getInstance(); // 以后再調(diào)用getInstance函數(shù)時(shí),返回第一次調(diào)用時(shí)創(chuàng)建的對(duì)象
Singleton& s3 = Singleton::getInstance(); // ...
cout << "&s1: " << &s1 << ", &s2: " << &s2 << ", &s3: " << &s3 << endl;
s1.releaseInstance( ); //
s2.releaseInstance( ); //
s3.releaseInstance( ); // 最后一次調(diào)用releaseInstance才將對(duì)象銷毀
return 0;
}
到了這里,關(guān)于cpp_07_類型轉(zhuǎn)換構(gòu)造_析構(gòu)函數(shù)_深拷貝_靜態(tài)成員的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!