我们假设我们有一个类如下:
class AbstractContainer{
...
};
template <typename T>
class Container : public AbstractContainer {
T someFunction();
};
现在还有另一个类,它有一个成员变量,可以存储其中一个容器。但是,模板类型不应修复。因此,不是将成员变量声明为Container
类型,而是声明为类型AbstractContainer*
,因此指向基类。无论模板参数如何,此指针都应该能够存储所有类型的Container
类。
class Interface{
public:
Interface();
void doSth();
private:
AbstractContainer* container;
};
我们假设容器是在Interface
类的构造函数中构造的,如下所示:
Interface::Interface(){
if (/* some condition */)
this->container = new Container<int>(25);
} else {
this->container = new Container<float>(25);
}
//here I'd need to remember of which type container is: int or float
}
所以在这里我需要以某种方式存储我的容器是哪种类型(int
或float
)。我知道它在我的程序的这一点,它是完全确定的。我需要存储它,因为稍后我可能需要将AbstractContainer*
转发回Container<int>*
或Container<float>*
,例如在另一个函数中:
void Interface::doSth(){
//here I have to recall what the type was
if(/* type was int */) {
dynamic_cast<Container<int>&>(*(this->container)).someFunction();
} else {
dynamic_cast<Container<float>&>(*(this->container)).someFunction();
}
}
我考虑过使用包含所有不同支持类型的值的enum
,并将该类型保存在该枚举类型的附加成员变量中。然后我必须制作一个switch
语句,检查所有不同的可能性并执行正确的演员表。但是,我想知道是否有更简单的方法。
我基本上喜欢做的是存储Interface
构造函数中使用的类型,然后在Interface::doSth
中调用它。
编辑:我必须明确函数someFunction
取决于模板参数T
。所以它不是一个让它成为虚拟的选择。
答案 0 :(得分:2)
你可以做
void Interface::doSth(){
if (auto* c_int = dynamic_cast<Container<int>*>(this->container)) {
c_int->someFunction();
} else if (auto* c_float = dynamic_cast<Container<float>*>(this->container)) {
c_float->someFunction();
}
}
但为什么不将someFunction()
移到基类中呢?并使用虚方法?
答案 1 :(得分:1)
虽然Jarod42's answer更好,但一种方法是使用typeid
:
void doSth()
{
if (typeid(*container).hash_code() == typeid(Container<int>).hash_code())
{
cout << "int" << endl;
}
else if (typeid(*container).hash_code() == typeid(Container<float>).hash_code())
{
cout << "float" << endl;
}
}
但是你需要在基类中至少有一个虚函数。例如,您可以创建一个虚拟析构函数。
答案 2 :(得分:1)
可能你的回答是Curiously recurring template pattern。
template<class T, template<class> class U>
class AbstractContainer
{
void interface()
{
static_cast<U<T> *>(this)->implementation();
}
};
template<class T>
class Container : public AbstractContainer<T, Container>
{
void implementation()
{
}
};
答案 3 :(得分:0)
另一种选择:
template <class T>
T doSth(Container<T> &container){
return container.someFunction(); //assume someFunction returns a T
}
你不需要基类,没有继承,没有演员阵容。
答案 4 :(得分:0)
class AbstactObject {
public:
virtual ~AbstractObject() = 0;
virtual AbstractObject &doSomething() = 0;
}
template<class T>
class Object : AbstactObject {
public:
virtual ~Object();
virtual Object<T> &doSomething();
T &get();
private:
T t;
}
class AbstractContainer {
public:
virtual ~AbstractObject() = 0;
virtual AbstractObject &doSomething();
private:
AbstractObject *obj;
};
template<class T>
class Container : AbstactContainer {
public:
virtual ~Container();
virtual Object<T> &doSomething() {
return obj->doSomething();
};
}
class Interface {
public:
Interface();
void doSth();
private:
AbstractContainer* container;
};
Interface::Interface() {
if (/* some condition */)
container = new Container<int>(25);
} else {
container = new Container<float>(25);
}
}
void Interface::doSth() {
auto obj = container->doSomething();
auto val = obj.get();
}
当你想获得T值
时auto obj = container->doSomething();
auto val = obj.get();
请检查:协变返回类型 https://en.wikipedia.org/wiki/Covariant_return_type