1.設計一個類,無法被拷貝。
方法:c++98,通過私有且只申明不實現(xiàn)拷貝構造與賦值函數,從而實現(xiàn)該類不能被拷貝。c++11引入關鍵字delete后,可以使構造構造與賦值函數等于delete。效果也是無法被拷貝。
2.設計一個類只能在堆上創(chuàng)建對象。
方法一,析構私有化
//實現(xiàn)一個類,智能在堆上創(chuàng)建對象
class HeapCreat
{
public:
HeapCreat()
{
cout << "調用構造" << endl;
}
void release()
{
delete this;
}
private:
//方法一 析構函數私有化
~HeapCreat()
{
cout << "調用析構" << endl;
}
方法二,構造私有化
class HeapCreat
{
public:
~HeapCreat()
{
cout << "調用析構" << endl;
}
void release()
{
delete this;
}
static HeapCreat* Creat()
{
return new HeapCreat;
}
//但是要禁用拷貝構造,拷貝出都在棧上,不在堆上
HeapCrea(const HeapCrea& p)=delete;
private:
HeapCreat()
{
cout << "調用構造" << endl;
}
//方案二 構造函數私有化
};
int main()
{
//構造函數私有化,最開始都初始化不了,因此只能在類里初始化,并且申明為全局,之后調用類里的初始化
HeapCreat* p = HeapCreat::Creat();
p->release();
return 0;
}
3.設計一個類只能在棧上創(chuàng)建對象。
方法一:
還是構造私有化,但是注意拷貝構造,我們拷貝構造可以new,但拷貝構造不能禁用,因為我們需要調用拷貝構造,故有缺陷
//構造私有化
//還是控制構造函數,在類中實現(xiàn)只能在棧上創(chuàng)建。
class HeapCreat
{
public:
~HeapCreat()
{
cout << "調用析構" << endl;
}
static HeapCreat Creat()
{
return HeapCreat();
}
HeapCreat( HeapCreat& p)=delete;
private:
HeapCreat()
{
cout << "調用構造" << endl;
}
};
int main()
{
HeapCreat p = HeapCreat::Creat();
return 0;
}
方法二,直接不讓使用new,申明出new并私有化,或delete.
class HeapCreat
{
public:
~HeapCreat()
{
cout << "調用析構" << endl;
}
static HeapCreat Creat()
{
return HeapCreat();
}
void* operator new(size_t t) = delete;
private:
//void* operator new(size_t t)
HeapCreat()
{
cout << "調用構造" << endl;
}
};
4.設計一個類,不能被繼承
同上,構造函數私有化,調不了就無法被繼承。
c++11提供了關鍵字final,可以是這個類不能為繼承,即最終類。
?一,何為設計模式
? ? 設計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。設計模式代表了最佳的實踐,通常被有經驗的面向對象的軟件開發(fā)人員所采用。就是前人總結下來的一些經驗。
設計模式分為三大類:創(chuàng)建型模式、結構型模式和行為型模式。
創(chuàng)建型模式包括工廠方法模式、抽象工廠模式、單例模式、建造者模式和原型模式。結構型模式包括適配器模式、橋接模式、組合模式、裝飾模式、外觀模式、享元模式和代理模式。行為型模式包括責任鏈模式、命令模式、解釋器模式、迭代器模式、中介者模式、備忘錄模式、觀察者模式、狀態(tài)模式、策略模式、模板方法模式和訪問者模式。
而創(chuàng)作型中常用的就是我們的單例模式,我們以學習單例模式來了解一下設計模式。
二,單例模式
所謂的單例模式其實本質上就是一個特殊類的設計。對于單例模式,在整個進程中,在整個全局環(huán)境中,只有這一個實例化的對象,即單實例,對于這樣的類的設計就是單例模式。對于大一點的項目,內存池等都會用到單例模式。
那么如是設計出全局下只有一個實例化對象?參考前面的博客,,特殊類的設計,那么要想只能實例化出一個對象,且是在全局的環(huán)境下,首先,我們要控制構造函數,讓其私有化,這樣在外面就無法實例化,對于構造提供了兩種方式,也就是單例模式的兩種模式。
其次就是要求在全局環(huán)境下的對象,直接在全局下創(chuàng)建首先無法實例化,構造函數已經私有化了,
且全局的對象是存在弊端的:對象是容易被修改的,多線程下會出現(xiàn)鏈接問題等。
之后了我們在類里創(chuàng)建對象,但直接創(chuàng)建顯然不可行,自己創(chuàng)建自己,但是當我們使用ststic時,就不是自己創(chuàng)建自己,該對象是在靜態(tài)區(qū)中。
因此最終我們選用靜態(tài)全局的方式實現(xiàn)單例模式。
餓漢模式
顧名思義,該模式很“饑餓”,我們在進入主程序前,就要把這個特殊類設計好給我,也就是在此之前,把對象給我來用。
class TEST
{
public:
//一般我們通過接口Getinstance 來獲取這個對象
static TEST* GetInstance() //對象是靜態(tài)對象
{
return &test;
}
void ADD(const string key, const string val)
{
dict.insert(make_pair(key, val));
}
void Print()
{
for (auto it : dict)
{
cout << it.first << ":" << it.second<<endl;
}
}
private:
//首先類的成員一般都是私有的,這里以一個字典為例
map <string, string> dict;
//私有構造并禁用拷貝與賦值
TEST()
{
}
TEST(const TEST& p) = delete;
TEST& operator=(const TEST& p) = delete;
static TEST test;//聲明 在靜態(tài)區(qū)當中
};
//定義
TEST TEST::test; //定義了一個類的對象test
int main()
{
//程序啟動 餓漢模式
TEST::GetInstance()->ADD("冒泡", "排序");//通過GetInstance獲取唯一的對象test
TEST::GetInstance()->ADD("希爾", "排序");
TEST::GetInstance()->Print();
return 0;
}
優(yōu)缺點:
優(yōu)點:實現(xiàn)簡單
缺點:可能導致進程啟動 ,如果有兩個單例啟動具有先后順序,控制不了餓漢。
懶漢模式
顧名思義,現(xiàn)吃現(xiàn)做,只有當我們需要使用這個對象的時候,我們才提供對象。即第一次使用的時候才創(chuàng)建。
//懶漢模式
class TEST
{
public:
static TEST* GetInstance()
{
//主程序要調用使用對象了此時我們在創(chuàng)建
//這里主要介紹懶漢的思想,實際上這里的代碼還存在線程安全問題
if (test == nullptr)
{
test = new TEST;
}
return test;
}
void ADD(const string key, const string val)
{
dict.insert(make_pair(key, val));
}
void Print()
{
for (auto it : dict)
{
cout << it.first << ":" << it.second<<endl;
}
}
static void Delete()
{
if (test)
{
delete test;
test = nullptr;
}
}
private:
//這里以一個字典為例
map <string, string> dict;
~TEST()
{
delete test;
}
TEST()
{
}
TEST(const TEST& p) = delete;
TEST& operator=(const TEST& p) = delete;
static TEST *test;//聲明 在靜態(tài)區(qū)當中
class gc
{
public:
~gc()
{
Delete();
}
};
static gc _gc;
};
//定義
TEST* TEST::test=nullptr;
TEST::gc TEST::_gc;
int main()
{
//程序啟動
//懶漢模式
TEST::GetInstance()->ADD("冒泡", "排序");//通過GetInstance獲取唯一的對象test
TEST::GetInstance()->ADD("希爾", "排序");
TEST::GetInstance()->Print();
}
釋放的時候,可以使用智能指針來管理這個指針,也可以在搞一個類用來處理析構,在該對象中,只要釋放,就會調用里面的類的的析構使得釋放指針。
類型轉換
c語言中的類型轉換
c語言的類型轉換分為兩種:
1.隱式類型轉換? :int i=1;double b=i;
對于能相互轉換的類型,可以隱式類型轉換。
2.顯式類型轉換 :? int j=1;doule ret=double(j)/0.1;
有關聯(lián)性的類型可以強制類型轉換。
c++的類型轉換
對于c語言的類型轉換,c++認為不太規(guī)范,因此c++提出了四種強制類型轉換的類型,只有這四類的類型才能強轉。
C++提供了四種強制類型轉換的函數:static_cast、dynamic_cast、const_cast和reinterpret_cast。
下面對這四種轉換操作的適用場景分別進行說明:
static_cast(靜態(tài)轉化): 該運算符把 expression 轉換為 type 類型,主要用于基本數據類型之間的轉換,如把 uint 轉換為 int,把 int 轉換為 double 等。此外,還可用于類層次結構中,基類和派生類之間指針或引用的轉換。
主要用于相近類型的轉化(對應c語言的隱式類型轉換的類型):
double i = 3.14159265;
int j = static_cast<int> (i) ;
dynamic_cast:(動態(tài)轉化) 主要用于類層次間的上行轉換或下行轉換。在進行上行轉換時dynamic_cast 和 static_cast 的效果是一樣的,但在下行轉換時,dynamic_cast 具有類型檢查的功能,比 static_cast 更安全。
const_cast:(常態(tài)轉化) 該運算符用來修改 expression 的 const 或 volatile 屬性。
去調const屬性,取地址在強轉為普通指針類型。
const int a = 10;
int* p = const_cast<int*>(&a);
*p = 3;
這里的a可能直接放寄存器了,也可能宏定義了。(不再去內存找這個值)?
因此雖然這里&a與p的地址一樣,但是值不一樣。利用關鍵字volatile使得強制去內存取值,我們就會發(fā)現(xiàn)兩個值是一樣的。其次在打印&a時,注意用printf,c++中的cout的輸出流在打印時沒有對應的函數。
reinterpret_cast: (重新詮釋轉化)該運算符可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針。這個轉換是“最不安全”的,不推薦使用
有一定關聯(lián),但是意義不相似的類型之間的轉換文章來源:http://www.zghlxwxcb.cn/news/detail-808513.html
int a = 1;
int* ptr = reinterpret_cast<int*> (a);
注意:類型轉換中間會產生臨時變量,二臨時變量具有常性,是不能被修改的(引用)。文章來源地址http://www.zghlxwxcb.cn/news/detail-808513.html
RTTI(了解)
到了這里,關于c++學習之特殊類設計與類型轉換的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!