假设我有具有一个成员的类模板pData
,这是一个AxB
arbitary类型的阵列T
。
template <class T> class X{
public:
int A;
int B;
T** pData;
X(int a,int b);
~X();
void print(); //function which prints pData to screen
};
template<class T>X<T>::X(int a, int b){ //constructor
A = a;
B = b;
pData = new T*[A];
for(int i=0;i<A;i++)
pData[i]= new T[B];
//Fill pData with something of type T
}
int main(){
//...
std::cout<<"Give the primitive type of the array"<<std::endl;
std::cin>>type;
if(type=="int"){
X<int> XArray(a,b);
} else if(type=="char"){
X<char> Xarray(a,b);
} else {
std::cout<<"Not a valid primitive type!";
} // can be many more if statements.
Xarray.print() //this doesn't work, as Xarray is out of scope.
}
作为if语句Xarray构造的内部的情况下,我不能用任何其他地方。 我尝试过的if语句,但作为指针的类型是未知的,在这一点上,我没有成功,使一个指针。
什么是处理这类问题的一个适当的方式?
C ++是一种静态类型语言,这意味着你必须知道的对象在编译时的类型。 在这种情况下,你是立足于用户输入构建的对象的类型,所以它不可能知道在运行时类型。
解决这一问题的最常见的方法是使用动态多态性在功能都通过一个共同的接口调用使用后期绑定 。 我们做到这一点在C ++中使用虚函数 。 例如:
struct IPrintable {
virtual void print() = 0;
};
template<class T>
class X : public IPrintable {
// Same code as you showed above.
};
int main() {
std::cout<<"Give the primitive type of the array"<<std::endl;
std::cin>>type;
std::unique_ptr<IPrintable> XArray;
if(type=="int"){
XArray.reset(new X<int>(a,b));
} else if(type=="char"){
XArray.reset(new X<char>(a,b));
} else {
std::cout<<"Not a valid primitive type!";
} // can be many more if statements.
Xarray->print() // this works now!
}
这解决了范围外的问题,并允许您使用动态类型XArray变量来打印。 虚拟函数是秘密武器,使这一切成为可能。
这里的问题是, X<int>
和x<char>
是完全无关的类型。
他们是同一个模板类的两种结果,这一事实将不利于在这里。
我可以看到几个解决方案,但这些取决于你真正需要的。
你可以例如使X<>
实例从具有共同的非模板化基类派生print()
方法(最终作为纯虚拟的)。 但你这样做之前,请确保它使在功能层面上的意义:因为它是有道理的,应该使用继承,因为不仅仅是技术上的限制。 如果你这样做,你可能会希望有一个虚析构函数,以及。
你也可以绑定和存储std::function<void ()>
您要调用该方法,但确保对象仍然“活着”(他们是不是在你的当前代码:无论是X<int>
和X<char>
,当他们走出去的范围实际上你打电话之前被破坏,这样print()
最后的解决办法是让一些变异类型,它是既兼容X<int>
和X<char>
( 升压::变种<>可以帮助这里)。 然后,你可以写一个实现了访问者print()
为每种类型的功能。
采摘最后的解决方案,它会成为这样的:
typedef boost::variant<X<int>, X<char>> genericX;
class print_visitor : public boost::static_visitor<void>
{
public:
template <typename SomeType>
void operator()(const SomeType& x) const
{
// Your print implementation
// x is your underlying instance, either X<char> or X<int>.
// You may also make several non-templated overloads of
// this operator if you want to provide different implementations.
}
};
int main()
{
boost::optional<genericX> my_x;
if (type=="int") {
my_x = X<int>(a,b);
} else if(type=="char") {
my_x = X<char>(a,b);
}
// This calls the appropriate print.
if (my_x) {
boost::apply_visitor(print_visitor(), *my_x)
}
}
实际上,我们缺乏足够的知识给出一个明确的答案:如果你的类是“实体”,那么你应该去继承。 如果他们更喜欢“值类”,那么变异的方法可能更适合。
而不是试图融入模板main
我会去比的建议休息相反的方式...移动码出 main
并到它自己的(可能是模板化)功能需要处理单一类型:
template <typename T>
void generateAndPrint(int a, int b) {
X<T> x(a,b);
x.print();
}
int main() { ...
if (type=="int") generateAndPrint<int>(a,b);
else if (type=="char") generateAndPrint<char>(a,b);
else ...
}
如果你想用不同的阵列的工作,无论其类型,单独模板可以帮不了你。 目前,恰好存在没有任何关系X<int>
和X<char>
。
如果你想将它们视为一种常见类型的两个亚型,你将不得不使用继承(和动态分配的变量)。 例如,所有X<T>
可以继承相同的基类,比方说Printable
,并且可以将数据存储在一个unique_ptr<Printable>
:
unique_ptr<Printable> r;
if(type=="int"){
r.reset(new X<int>(a,b));
} else if(type=="char"){
r.reset(new X<char>(a,b);
}
r->print();
但是,这可能不是最好的设计。
一个可能更好的解决办法是,而不是试图将如果在外面工作,以移动,如果内部的所有工作。 在您简单的例子,这可以通过复制调用打印完成,但是这要么是不是相当不错。 但是,对于这样的想法去,我们可以创建一个模板函数,它的工作:
template<class T>
void workWithType(int a, int b)
{
X<T> Xarray(a, b);
Xarray.print();
}
//...
if(type=="int"){
workWithType<int>(a,b);
} else if(type=="char"){
workWithType<char>(a,b);
}