5,530
社区成员
发帖
与我相关
我的任务
分享
///C++ 模板类中有类自身的静态成员变量
template<typename _Ty>
Class A
{
public:
A()
{
}
~A()
{
}
static A* _instance;
}
template<typename _Ty>
A<_Ty> * A<_Ty>::_instance = NULL;
template<>
Class A<int>
{
public:
A()
{
}
~A()
{
}
static A* _instance;
}
A<int> * A<int>::_instance = NULL;
///这样偏特化静态成员变量初始化后,一旦有两个文件包含该头文件。就会报 A<int>* A<int>::_instance 已经在先编译的cpp文件中定义的链接错误。请问有什么好的解决办法。还望不吝赐教
A<int> * A<int>::_instance = NULL;
放cpp文件里。
#pragma once // 加上这个?当然也可以是宏定义的方式
template<typename _Ty>
class A
{
public:
A()
{
}
~A()
{
}
static A* _instance;
};
template<typename _Ty>
A<_Ty> * A<_Ty>::_instance = NULL;
template<>
class A<int>
{
public:
A()
{
}
~A()
{
}
static A* _instance;
};
A<int> * A<int>::_instance = NULL;
///那样会报无法解析外部符号A<int> * A<int>::_instance 错误。
[/quote]
有没包含对应的头文件?[/quote]头文件肯定会包含的
#pragma once
template<typename _Ty>
class A
{
public:
A()
{
}
~A()
{
}
static A* _instance;
};
template<typename _Ty>
A<_Ty> * A<_Ty>::_instance = NULL;
template<>
class A<int>
{
public:
A()
{
}
~A()
{
}
static A* _instance;
};
A<int> * A<int>::_instance = NULL;
Singleton.h
#pragma once
#include "a.h"
#include <iostream>
using namespace std;
class CContrlCenter
{
public:
static CContrlCenter *GetInstance()
{
static CContrlCenter instance;
A<char> ca;
cout << "ca " << "befroeSet " << ca._instance << endl;
ca._instance = &ca;
cout << "ca " << "afterSet " << ca._instance << endl;
return &instance;
}
private:
CContrlCenter() {};
};
Singleton.cpp
/*--------------------------------------------------------------------------------------
一、概念
单例模式:其意图是保证一个雷仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
class CContrlCenter
{
//公有的静态方法,来获取该实例
public:
static CContrlCenter* GetInstance()
{
if ( m_pInstance == NULL ) //判断是否第一次调用
m_pInstance = new CContrlCenter();
return m_pInstance;
}
//私有构造函数,防止实例化
private:
CContrlCenter(){};
//私有静态指针变量,指向类的唯一实例
private:
static CContrlCenter * m_pInstance; //声明一个静态成员
};
CContrlCenter* CContrlCenter::m_pInstance = NULL; //定义并初始化静态数据成员
int main()
{
CContrlCenter* ps1 = CContrlCenter::GetInstance();
CContrlCenter* ps2 = CContrlCenter::GetInstance();
CContrlCenter* ps3 = ps1->GetInstance();
CContrlCenter & ps4 = * CContrlCenter :: GetInstance();
if (ps1 == ps2)
{
cout<< "ps1 = ps2"<<endl;
}
if (ps1 == ps3)
{
cout<< "ps1 = ps3"<<endl;
}
if (&ps4 == ps1)
{
cout<< "ps1 = ps4"<<endl;
}
return 0;
}
单例模式通过类本身来管理其唯一实例,唯一的实例是类的一个普通对象,但涉及这个类时,让它只能创建一个实例,并提供对此实例的全局访问。
用户访问唯一实例的方法只有GetInstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。
有一点要注意:一定要加上CContrlCenter* CContrlCenter::m_pInstance = NULL; 这一句,不然的话编译会出错,因为这一句才有变量定义。
二、单例类CContrlCenter有一下特征
它有一个指向唯一实例的静态指针m_Instance,并且是私有的;
它有一个公有的函数,可以获取这个唯一的实例,并且在需要的时候创建该实例;
它的构造函数是私有的,这样就不能从别处创建该类的实例。
三、存在的问题
1.m_pInstance指向的空间什么时候释放呢?
如果在类的西沟行为中有必须的操作,比如关闭文件,释放外部资源,那么上面的代码无法实现这个要求。我们需要一种方法,正常的删除该实例。
不合理的解决方法:
程序结束时调用GetInstance(),并对返回的指针调用delete操作。这样可以实现功能,但不仅很丑陋,而且容易出错。因为这样的附加代码很容易被忘记,而且也很难保证在delete之后,没有代码再调用GetInstance函数。也就是说释放操作由使用者来管理,而不是类本身来管理,这违背了类的单一原则,这是不合理的。
2.该实例的析构函数什么时候执行?
上面类里面为什么没有析构函数,其实即便你加上析构函数也是可以的,但是这个析构函数不会被执行的。因为你的实例是new出来的,所以只有delete时,才会调用析构函数,但是在哪里调用delete呢?这又回到了上面的问题。
一种妥善的方法:
class CContrlCenter
{
public:
static CContrlCenter* GetInstance()
{
static CContrlCenter instance; //静态局部变量
return &instance;
}
private:
CContrlCenter() {}; //构造函数
};
--------------------------------------------------------------------------------------*/
#include <iostream>
#include "A.h"
#include "Singleton.h"
using namespace std;
int main()
{
CContrlCenter *ps1 = CContrlCenter::GetInstance();
CContrlCenter *ps2 = CContrlCenter::GetInstance();
CContrlCenter *ps3 = CContrlCenter::GetInstance();
CContrlCenter &ps4 = *CContrlCenter::GetInstance();
if (ps1 == ps2)
{
cout << "ps1 = ps2" << endl;
}
if (ps1 == ps3)
{
cout << "ps1 = ps3" << endl;
}
if (ps1 == &ps4)
{
cout << "ps1 = ps4" << endl;
}
A<int> ia;
cout << "ia " << "beforeSet " << ia._instance << endl;
ia._instance = &ia;
cout << "ia " << "afterSet " << ia._instance << endl;
A<double> da;
cout << "da " << "beforeSet " << da._instance << endl;
da._instance = &da;
cout << "da " << "afterSet " <<da._instance << endl;
return 0;
}
[/quote]打了好多,你可以试一下,在另一个.h 或.cpp文件 中 包含a.h文件,会报错的。
我用另一种方式规避了这个问题。但我想知道,按照类的形式进行模板特化 或者 偏特化 类中 静态成员变量的 初始化 应该 怎么写 才能 在多个 文件中进行。打这么多辛苦了!不管怎样先感谢下!
#pragma once
template<typename _Ty>
class A
{
public:
A()
{
}
~A()
{
}
static A* _instance;
};
template<typename _Ty>
A<_Ty> * A<_Ty>::_instance = NULL;
template<>
class A<int>
{
public:
A()
{
}
~A()
{
}
static A* _instance;
};
A<int> * A<int>::_instance = NULL;
Singleton.h
#pragma once
#include "a.h"
#include <iostream>
using namespace std;
class CContrlCenter
{
public:
static CContrlCenter *GetInstance()
{
static CContrlCenter instance;
A<char> ca;
cout << "ca " << "befroeSet " << ca._instance << endl;
ca._instance = &ca;
cout << "ca " << "afterSet " << ca._instance << endl;
return &instance;
}
private:
CContrlCenter() {};
};
Singleton.cpp
/*--------------------------------------------------------------------------------------
一、概念
单例模式:其意图是保证一个雷仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
class CContrlCenter
{
//公有的静态方法,来获取该实例
public:
static CContrlCenter* GetInstance()
{
if ( m_pInstance == NULL ) //判断是否第一次调用
m_pInstance = new CContrlCenter();
return m_pInstance;
}
//私有构造函数,防止实例化
private:
CContrlCenter(){};
//私有静态指针变量,指向类的唯一实例
private:
static CContrlCenter * m_pInstance; //声明一个静态成员
};
CContrlCenter* CContrlCenter::m_pInstance = NULL; //定义并初始化静态数据成员
int main()
{
CContrlCenter* ps1 = CContrlCenter::GetInstance();
CContrlCenter* ps2 = CContrlCenter::GetInstance();
CContrlCenter* ps3 = ps1->GetInstance();
CContrlCenter & ps4 = * CContrlCenter :: GetInstance();
if (ps1 == ps2)
{
cout<< "ps1 = ps2"<<endl;
}
if (ps1 == ps3)
{
cout<< "ps1 = ps3"<<endl;
}
if (&ps4 == ps1)
{
cout<< "ps1 = ps4"<<endl;
}
return 0;
}
单例模式通过类本身来管理其唯一实例,唯一的实例是类的一个普通对象,但涉及这个类时,让它只能创建一个实例,并提供对此实例的全局访问。
用户访问唯一实例的方法只有GetInstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。
有一点要注意:一定要加上CContrlCenter* CContrlCenter::m_pInstance = NULL; 这一句,不然的话编译会出错,因为这一句才有变量定义。
二、单例类CContrlCenter有一下特征
它有一个指向唯一实例的静态指针m_Instance,并且是私有的;
它有一个公有的函数,可以获取这个唯一的实例,并且在需要的时候创建该实例;
它的构造函数是私有的,这样就不能从别处创建该类的实例。
三、存在的问题
1.m_pInstance指向的空间什么时候释放呢?
如果在类的西沟行为中有必须的操作,比如关闭文件,释放外部资源,那么上面的代码无法实现这个要求。我们需要一种方法,正常的删除该实例。
不合理的解决方法:
程序结束时调用GetInstance(),并对返回的指针调用delete操作。这样可以实现功能,但不仅很丑陋,而且容易出错。因为这样的附加代码很容易被忘记,而且也很难保证在delete之后,没有代码再调用GetInstance函数。也就是说释放操作由使用者来管理,而不是类本身来管理,这违背了类的单一原则,这是不合理的。
2.该实例的析构函数什么时候执行?
上面类里面为什么没有析构函数,其实即便你加上析构函数也是可以的,但是这个析构函数不会被执行的。因为你的实例是new出来的,所以只有delete时,才会调用析构函数,但是在哪里调用delete呢?这又回到了上面的问题。
一种妥善的方法:
class CContrlCenter
{
public:
static CContrlCenter* GetInstance()
{
static CContrlCenter instance; //静态局部变量
return &instance;
}
private:
CContrlCenter() {}; //构造函数
};
--------------------------------------------------------------------------------------*/
#include <iostream>
#include "A.h"
#include "Singleton.h"
using namespace std;
int main()
{
CContrlCenter *ps1 = CContrlCenter::GetInstance();
CContrlCenter *ps2 = CContrlCenter::GetInstance();
CContrlCenter *ps3 = CContrlCenter::GetInstance();
CContrlCenter &ps4 = *CContrlCenter::GetInstance();
if (ps1 == ps2)
{
cout << "ps1 = ps2" << endl;
}
if (ps1 == ps3)
{
cout << "ps1 = ps3" << endl;
}
if (ps1 == &ps4)
{
cout << "ps1 = ps4" << endl;
}
A<int> ia;
cout << "ia " << "beforeSet " << ia._instance << endl;
ia._instance = &ia;
cout << "ia " << "afterSet " << ia._instance << endl;
A<double> da;
cout << "da " << "beforeSet " << da._instance << endl;
da._instance = &da;
cout << "da " << "afterSet " <<da._instance << endl;
return 0;
}
///那样会报无法解析外部符号A<int> * A<int>::_instance 错误。
[/quote]
有没包含对应的头文件?///那样会报无法解析外部符号A<int> * A<int>::_instance 错误。