我如何解决这个问题?我显然无法将value()方法设为虚拟,因为我事先不知道它是什么类型,并且在从b访问方法时可能不知道这一点:
class Base
{
public:
Base() { }
virtual ~Base() { }
private:
int m_anotherVariable;
};
template <typename T>
class Derived : public Base
{
public:
Derived(T value) : m_value(value) { }
~Derived() { }
T value() { return m_value; }
void setValue(T value) { m_value = value; }
private:
T m_value;
};
int main()
{
Base* b = new Derived<int>(5);
int v = b->value();
return 0;
}
编译错误:
error: 'class Base' has no member named 'value'
答案 0 :(得分:3)
本声明:
int v = b->value();
变量'b'被捕获,就像它是Derived&lt; int&gt;的对象一样 所以告诉编译器:
int v = dynamic_cast<Derived<int>*>(b)->value();
注意:如果b不是Derived&lt; int&gt;演员的结果是NULL 所以以下可能会更安全:
Derived<int>* d = dynamic_cast<Derived<int>*>(b);
if (d)
{
int v = d->value();
}
else
{
// Error
}
或者通过使用引用,您将获得抛出的bad_cast异常:
// Throw bad_cast on failure.
Derived<int>& d = dynamic_cast<Derived<int>&>(*b);
int v = d->value();
或者为了善良和模糊,我们可以做到一行。
// Assign v or throw bad_cast exception:
int v = dynamic_cast<Derived<int>&>(*b).value();
但我认为你可以通过boost :: any
实现你想要做的事情int main()
{
boost::any b(5);
int v = boost::any_cast<int>(b);
b = 5.6; // double
double d = boost::any_cast<double>(b);
}
答案 1 :(得分:2)
如果您提出这个问题(根据我的经验,我的设计),我认为可能会对您的设计造成一些问题。
但是,有一些解决方法:
但这里真正的问题是你试着在这里描述什么? Base,Derived和value()的含义是什么?问自己这些问题,你可能不需要这些答案......
答案 2 :(得分:1)
一些解决方案:
template < typename T>
class Base{
public:
Base() { }
virtual ~Base() { }
virtual T value() = 0;
private:
int m_anotherVariable;
};
template <typename T>
class Derived : public Base<T> {
...
}
int main(){
Base<int>* b = new Derived<int>(5);
int v = b->value();
return 0;
}
另一种解决方案:
class Base {
public:
Base() { }
virtual ~Base() { }
template<class T> T value() const;
private:
int m_anotherVariable;
};
template <typename T>
class Base2 : public Base {
public:
Base2() { }
virtual ~Base2() { }
virtual T getValue() const = 0;
};
template<class T> T Base::value() const {
const Base2<T> * d = dynamic_cast<const Base2<T> *>(this);
return d ? d->getvalue() : T();
}
template <typename T>
class Derived : public Base2<T> {
public:
Derived(T value) : m_value(value) { }
virtual ~Derived() { }
void setValue(T value) { m_value = value; }
virtual T getValue() const { return m_value; }
private:
T m_value;
}
int main(){
Base* b = new Derived<int>(5);
int v = b->value<int>();
return 0;
}
答案 3 :(得分:0)
在这种情况下,Base需要知道模板类型,因此b-&gt; value返回T。
我建议将模板添加到Base,然后在Base
上将值设为虚函数答案 4 :(得分:0)
您可以将指针投射到Derived
:
int v = dynamic_cast<Derived<int>*>(b)->value();
当然,在实际代码中,您必须添加检查以确保dynamic_cast
没有失败。
答案 5 :(得分:0)
为什么不制作基于模板的基类呢?然后,您可以将值作为虚拟成员。
或者你可以将b转发给Derived。
答案 6 :(得分:0)
看起来你想要动态多态,但只使用模板的“静态多态”。
如果你想要动态多态,你确实需要基类中的虚拟成员(以及你的虚拟析构函数)或者如果你没有公共接口那么需要down_cast。
如果没有,请删除虚拟析构函数,仅使用指向派生类型的指针或实例。
关于Base作为模板:
它将阻止您将动态多态性的单个基类作为Base&lt; int&gt;和基地&lt;其他&gt;将是不兼容的。
答案 7 :(得分:0)
处理此问题的一种方法是通过visitor pattern。基本思想是,在您的类层次结构中,您实现了一个接受访问者的onNode
函数。然后,您编写符合您需要的特定访问者。在你的情况下,你最终得到:
class GetIntValue : public BaseVisitor
{
public:
GetIntValue (int & result)
: m_result (result) {}
void onNode (Derived<int> & d)
{
m_result = d.m_value;
}
void onNode (Derived<A> & d)
{
assert (! "calling GetIntValue on a node that doesn't have a value");
}
private:
int & m_result;
};
int main()
{
Base* b = new Derived<int>(5);
int v;
GetIntValue(v).visit (*b);
return 0;
}