【面試題二】java實現的單例模式,c++實現單例模式,實現禁止拷貝

一 c++實現單例模式

保證一個類,在一個程序當中只有一個對象,只有一個實例,這個對象要禁止拷貝,注意這裏要區別於java。否者的話一個程序當中就可能出現多個對象的拷貝。

我們要禁止拷貝,需要將拷貝構造函數以及等號運算符 聲明爲私有的,並且呢不提供他們的實現。這樣子如果我們代碼裏面有拷貝構造的話,編譯時候會出錯。


僅僅這樣子是不夠的,我們必須將構造函數聲明爲私有的,這是爲了防止外部呢,任意的構造對象。


既然我們將構造函數私有化了,外部就不能通過 Singleton s1; 來定義這樣一個對象。那我們就需要提供一個接口讓外部呢得到這樣一個對象。

Singleton.cpp:

#include <iostream>
#include <memory>
using namespace std;

class Singleton
{
public:
	/*這個GetInstance是靜態的由類直接調用的*/
	static Singleton* GetInstance()
	{

		/*用這種方法會出現構造出來的這個對象什麼時候釋放的問題*/
/*		if (instacne_ == NULL)
		{
			instacne_ = new Singleton;
		}
		return instacne_;*/

		/* 把裸指針用智能指針來管理
         * 智能指針是重載了點號運算符的,我們訪問類本身的get()方法,獲得裸指針
		 */
		if (!instacne_.get())
		{
			instacne_ = auto_ptr<Singleton>(new Singleton);
		}

		return instacne_.get();
	}

	~Singleton()
	{
		cout<<"~Singleton ..."<<endl;
	}
private:
	// 禁止拷貝--構造函數和等號運算符聲明爲私有的,並且不提供實現。
	Singleton(const Singleton& other);
	Singleton& operator=(const Singleton& other);

	// 將構造函數說明爲私有的
	Singleton()
	{
		cout<<"Singleton ..."<<endl;
	}
	/*這實際上是一個靜態的類對象,這裏僅僅是引用性說明,她的定義應該在類的外邊*/
	static auto_ptr<Singleton> instacne_;
};

/*定義性說明*/
auto_ptr<Singleton> Singleton::instacne_;

int main(void)
{
	//Singleton s1;
	//Singleton s2;

	Singleton* s1 = Singleton::GetInstance();
	Singleton* s2 = Singleton::GetInstance();

	//Singleton s3(*s1);		// 調用拷貝構造函數

	return 0;
}



Makefile:

.PHONY:clean
CPP=g++
CFLAGS=-Wall -g
BIN=test
OBJS=Singleton.o
LIBS=
$(BIN):$(OBJS)
	$(CPP) $(CFLAGS) $^ -o $@ $(LIBS)
%.o:%.cpp
	$(CPP) $(CFLAGS) -c $< -o $@
clean:
	rm -f *.o $(BIN)

運行結果

Singleton ...
~Singleton ...


裸指針呢,用智能指針來管理靜態的一個類對象,當整個程序結束的時候,靜態對象也就被銷燬了,

那麼靜態對象的銷燬就會導致這個類對象的析構函數被調用,

instance_.get()
這個get()方法是 智能指針提供的是吧
auto_ptr中有個get方法
還有你給的析構函數  裏面並沒有釋放 那個指針所指的資源 
是程序結束的時候,由智能指針來釋放的

智能指針變量 本身不是堆區內存,
智能指針對象銷燬的時候,智能指針對象的析構函數會去銷燬它所包裹的堆對象

只不過說 智能指針釋放了,靜態的變量的時候會調用這個變量的析構函數

析構函數是,delete的時候調用的,這個delete操作是在智能指針對象的析構函數中調用的,從而引發了堆對象的析構

如果正常調用析構函數的情況,析構函數你是需要自己是釋放對象的資源的,(因爲是堆對象,堆上的東西自己釋放)


	//Singleton s1;
	//Singleton s2;

	//Singleton s3(*s1);		// 調用拷貝構造函數

這些情況下都是錯誤的,

運行結果:

g++ -Wall -g -c Singleton.cpp -o Singleton.o
Singleton.cpp: 在函數‘int main()’中:
Singleton.cpp:36:2: 錯誤: ‘Singleton::Singleton(const Singleton&)’是私有的
Singleton.cpp:59:18: 錯誤: 在此上下文中
Singleton.cpp:57:13: 警告: 未使用的變量‘s2’ [-Wunused-variable]
make: *** [Singleton.o] 錯誤 1


二,實現禁止拷貝


Nocopyable這個類如何保證禁止拷貝,她的實現和Singleton類的實現差不多。

Noncopyable.cpp:

#include <iostream>
#include <memory>
using namespace std;

class Noncopyable
{
protected:
	Noncopyable() {}
	~Noncopyable() {}
private:
	Noncopyable(const Noncopyable&);
	const Noncopyable& operator=(const Noncopyable&);
};


class Parent : private Noncopyable
{
public:
	Parent()
	{

	}
	Parent(const Parent& other) : Noncopyable(other)
	{

	}
};

class Child : public Parent
{
public:
	//Child(const Child& other)
	//{

	//}
};

int main()
{
	/*這兩種情況都是失敗的*/
	//Parent p1;
	//Parent p2(p1);		// 要調用Parent拷貝構造函數,Parent構造函數又調用Noncopyable的拷貝構造函數

	Child c1;
	Child c2(c1);
	return 0;
}

注意:

private 是實現繼承,並不是爲了繼承她的接口

public 是接口繼承


Makefile:

.PHONY:clean
CPP=g++
CFLAGS=-Wall -g
BIN=test
OBJS=Noncopyable.o
LIBS=
$(BIN):$(OBJS)
	$(CPP) $(CFLAGS) $^ -o $@ $(LIBS)
%.o:%.cpp
	$(CPP) $(CFLAGS) -c $< -o $@
clean:
	rm -f *.o $(BIN)

運行結果:

g++ -Wall -g -c Noncopyable.cpp -o Noncopyable.o
Noncopyable.cpp: 在複製構造函數‘Parent::Parent(const Parent&)’:
Noncopyable.cpp:11:2: 錯誤: ‘Noncopyable::Noncopyable(const Noncopyable&)’是私有的
Noncopyable.cpp:23:49: 錯誤: 在此上下文中
make: *** [Noncopyable.o] 錯誤 1


這裏我們需要注意的地方是,

對於構造函數來說,如果基類有默認構造函數,即使我們沒有寫 :Noncopyable()這句話,他也是會自動調用基類的默認構造函數的,

但是拷貝構造函數就不一樣啦,如果我們沒有寫 :Noncopyable(other)這句話,是不會調用基類的拷貝構造函數的,

當然如果基類沒有默認的構造函數,那麼這個時候呢,一定要在成員列表中給出對基類構造函數的調用。




JAVA實現的單例模式:

讀取配置文件,並且實例化了一個對象,這個對象保證只有一個。

package com.ebupt.ebms.conf;

/**
 * @author zling Create on 2011-3-7
 * @version 1.0
 */
public class MainConfig {

	private boolean useCache = true;// 是否緩存

	private boolean videoConvert = false;// 是否進行視頻格式轉換
	
	private boolean useMail = true;//是否進行郵件通知

	private Integer sessionTimeOut = 3 * 60 * 1000;

	private String logPath = ""; // 上傳的各種日誌的本地路徑

	private String webPath = ""; // 播放任務描述文件基路徑,播放列表和資源清單均在該基路徑下

	private String urlPath = ""; // 終端訪問基路徑,可爲http或ftp的基路徑

	private String tomcatPath = ""; // Tomcat 服務器所在路徑

	private String phoneNumber = "";// 維護人員手機號碼,多個之間用逗號分隔
	
	private String email = "";// 維護人員郵箱地址,多個之間用逗號分隔

	private String mailServer = "";// 郵箱服務器地址

	private String mailAccount = "";// 郵箱賬號

	private String mailPasswd = "";// 郵箱密碼
	
	private String ltpasso = "";// 北京移動基於LTPA方式的SSO
	
	private String sitesso = "";// 北京移動基於SiteMinder方式的SSO
	
	private String ssourl = "";// SSO的服務路徑
	
	private String fouraurl = "";// 4A賬號操作相關的rul
	private String fouracheckurl = "";// 4A校驗相關的url
	
	private String redirecturl = "";// 驗證成功後跳轉到的路徑
	
	private String localfourapath = "";// 本地存放生成的4a日誌文件的路徑
	private String fouraftpurl = "";// 4aftp的url
	private String fouraftpport = "";// 4aftp的port
	private String fouraftpname = "";// 4aftp的username
	private String fouraftppwd = "";// 4aftp的password
	private String fouraftpsavepath = "";// 4aftp保存文件的路徑
	private String fouraftpfilename = "";// 4a要求的上傳到ftp服務器的日誌文件的名稱


	private static MainConfig instance = new MainConfig();//懶人模式

	public static MainConfig getInstance() {
		if (instance == null)
			instance = new MainConfig();
		return instance;
	}

	public String string() {

		StringBuffer sb = new StringBuffer();
		sb.append("logPath : ").append(logPath).append("\n");
		sb.append("webPath : ").append(webPath).append("\n");
		sb.append("urlPath : ").append(urlPath).append("\n");
		sb.append("tomcatPath : ").append(tomcatPath).append("\n");
		sb.append("useCache : ").append(useCache).append("\n");
		sb.append("useMail : ").append(useMail).append("\n");
		sb.append("videoConvert : ").append(videoConvert).append("\n");
		sb.append("sessionTimeOut : ").append(sessionTimeOut).append("\n");
		sb.append("phoneNumber : ").append(phoneNumber).append("\n");
		sb.append("email : ").append(email).append("\n");
		sb.append("mailServer : ").append(mailServer).append("\n");
		sb.append("mailAccount : ").append(mailAccount).append("\n");
		sb.append("mailPasswd : ").append(mailPasswd).append("\n");
		sb.append("ltpasso : ").append(ltpasso).append("\n");
		sb.append("sitesso : ").append(sitesso).append("\n");
		sb.append("ssourl : ").append(ssourl).append("\n");
		sb.append("fouraurl : ").append(fouraurl).append("\n");
		sb.append("fouracheckurl : ").append(fouracheckurl).append("\n");
		sb.append("redirecturl : ").append(redirecturl).append("\n");
		sb.append("localfourapath : ").append(localfourapath).append("\n");
		sb.append("fouraftpurl : ").append(fouraftpurl).append("\n");
		sb.append("fouraftpport : ").append(fouraftpport).append("\n");
		sb.append("fouraftpname : ").append(fouraftpname).append("\n");
		sb.append("fouraftppwd : ").append(fouraftppwd).append("\n");
		sb.append("fouraftpsavepath : ").append(fouraftpsavepath).append("\n");
		sb.append("fouraftpfilename : ").append(fouraftpfilename).append("\n");
		return sb.toString();
	}

	public boolean isUseCache() {
		return useCache;
	}

	public void setUseCache(boolean useCache) {
		this.useCache = useCache;
	}

	public boolean isUseMail() {
		return useMail;
	}

	public void setUseMail(boolean useMail) {
		this.useMail = useMail;
	}

	public boolean isVideoConvert() {
		return videoConvert;
	}

	public void setVideoConvert(boolean videoConvert) {
		this.videoConvert = videoConvert;
	}

	public Integer getSessionTimeOut() {
		return sessionTimeOut;
	}

	public void setSessionTimeOut(Integer sessionTimeOut) {
		this.sessionTimeOut = sessionTimeOut;
	}

	public String getLogPath() {
		return logPath;
	}

	public void setLogPath(String logPath) {
		this.logPath = logPath;
	}

	public String getWebPath() {
		return webPath;
	}

	public void setWebPath(String webPath) {
		this.webPath = webPath;
	}

	public String getUrlPath() {
		return urlPath;
	}

	public void setUrlPath(String urlPath) {
		this.urlPath = urlPath;
	}

	public String getTomcatPath() {
		return tomcatPath;
	}

	public void setTomcatPath(String tomcatPath) {
		this.tomcatPath = tomcatPath;
	}

	public String getPhoneNumber() {
		return phoneNumber;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}

	public String getMailServer() {
		return mailServer;
	}

	public void setMailServer(String mailServer) {
		this.mailServer = mailServer;
	}

	public String getMailAccount() {
		return mailAccount;
	}

	public void setMailAccount(String mailAccount) {
		this.mailAccount = mailAccount;
	}

	public String getMailPasswd() {
		return mailPasswd;
	}

	public void setMailPasswd(String mailPasswd) {
		this.mailPasswd = mailPasswd;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getLtpasso() {
		return ltpasso;
	}

	public void setLtpasso(String ltpasso) {
		this.ltpasso = ltpasso;
	}

	public String getSitesso() {
		return sitesso;
	}

	public void setSitesso(String sitesso) {
		this.sitesso = sitesso;
	}

	public String getSsourl() {
		return ssourl;
	}

	public void setSsourl(String ssourl) {
		this.ssourl = ssourl;
	}
	
	public String getFouraurl() {
		return fouraurl;
	}

	public void setFouraurl(String fouraurl) {
		this.fouraurl = fouraurl;
	}

	public String getRedirecturl() {
		return redirecturl;
	}

	public void setRedirecturl(String redirecturl) {
		this.redirecturl = redirecturl;
	}

	public String getLocalfourapath() {
		return localfourapath;
	}

	public void setLocalfourapath(String localfourapath) {
		this.localfourapath = localfourapath;
	}

	public String getFouraftpurl() {
		return fouraftpurl;
	}

	public void setFouraftpurl(String fouraftpurl) {
		this.fouraftpurl = fouraftpurl;
	}

	public String getFouraftpport() {
		return fouraftpport;
	}

	public void setFouraftpport(String fouraftpport) {
		this.fouraftpport = fouraftpport;
	}

	public String getFouraftpname() {
		return fouraftpname;
	}

	public void setFouraftpname(String fouraftpname) {
		this.fouraftpname = fouraftpname;
	}

	public String getFouraftppwd() {
		return fouraftppwd;
	}

	public void setFouraftppwd(String fouraftppwd) {
		this.fouraftppwd = fouraftppwd;
	}

	public String getFouraftpfilename() {
		return fouraftpfilename;
	}

	public void setFouraftpfilename(String fouraftpfilename) {
		this.fouraftpfilename = fouraftpfilename;
	}

	public String getFouraftpsavepath() {
		return fouraftpsavepath;
	}

	public void setFouraftpsavepath(String fouraftpsavepath) {
		this.fouraftpsavepath = fouraftpsavepath;
	}

	public String getFouracheckurl() {
		return fouracheckurl;
	}

	public void setFouracheckurl(String fouracheckurl) {
		this.fouracheckurl = fouracheckurl;
	}
	
	
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章