[英]Accessing a method from a templated derived class without using virtual functions in c++?
How do I get around this? 我该如何解决? I clearly cannot make the value() method virtual as I won't know what type it is beforehand, and may not know this when accessing the method from b: 我显然不能使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;
}
Compilation errors: 编译错误:
error: 'class Base' has no member named 'value'
This statement: 这个说法:
int v = b->value();
The variable 'b' is being trated like it is an object of Derived<int>. 变量'b'被当作Derived <int>的对象进行处理。
So tell the compiler: 因此,告诉编译器:
int v = dynamic_cast<Derived<int>*>(b)->value();
Note: If b is not a Derived<int> the result of the cast is NULL. 注意:如果b不是Derived <int>,则强制转换的结果为NULL。
So the following would probably be safer: 因此,以下内容可能会更安全:
Derived<int>* d = dynamic_cast<Derived<int>*>(b);
if (d)
{
int v = d->value();
}
else
{
// Error
}
Alternatively by using references you get a bad_cast exception thrown: 或者,通过使用引用,您会抛出bad_cast异常:
// Throw bad_cast on failure.
Derived<int>& d = dynamic_cast<Derived<int>&>(*b);
int v = d->value();
Or to be nice and obscrure we can do it one line. 或者,要变得晦涩难懂,我们可以一行完成。
// Assign v or throw bad_cast exception:
int v = dynamic_cast<Derived<int>&>(*b).value();
But I think you can achieve what you are trying to do with the boost::any 但是我认为您可以通过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);
}
I think there may be some problems with your design if you ask this question (from my experience, with my designs). 我认为,如果您问这个问题(根据我的经验和我的设计),您的设计可能会有一些问题。
However, there are some workarounds: 但是,有一些解决方法:
But the real question here is what do you try to describe here? 但是,这里真正的问题是您试图在这里描述什么? What is the meaning of Base, Derived and value(). Base,Derived和value()的含义是什么。 Ask yourself these question and you may not need these answers... 问自己这些问题,您可能不需要这些答案...
Some solution: 一些解决方案:
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;
}
Another solution: 另一个解决方案:
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;
}
In this case Base will need to know about the template type so b->value returns a T. 在这种情况下,Base需要了解模板类型,因此b-> value返回T。
I would suggest adding the template to Base and then make value a virtual function on Base 我建议将模板添加到Base,然后在Base上使值成为虚拟函数
You could cast your pointer to Derived
: 您可以将指针投射到Derived
:
int v = dynamic_cast<Derived<int>*>(b)->value();
Of course in real code, you have to add checking to make sure that dynamic_cast
didn't fail. 当然,在实际代码中,您必须添加检查以确保dynamic_cast
不会失败。
Why don't make Base template-based class too? 为什么也不要使基于Base模板的类呢? Then you can have value as a virtual member. 然后,您可以作为虚拟成员而有价值。
Or you can downcast b to Derived. 或者,您可以将b降为Derived。
It looks like you want dynamic polymorphism but using only the "static polymorphism" of templates. 看起来您想要动态多态性,但仅使用模板的“静态多态性”。
If you want dynamic polymorphism you do need virtual members in your base class ( along with your virtual destructor ) or the down_cast if you do not have a common interface. 如果要动态多态性,则确实需要基类中的虚拟成员(以及虚拟析构函数),或者如果没有通用接口,则需要down_cast。
If not, remove the virtual destructor and use only pointers to or instances of derived types. 如果没有,请删除虚拟析构函数,并仅使用指向派生类型的指针或实例。
About Base as a template : 关于Base作为模板:
It will prevent you from having a single base class for dynamic polymorphism as Base< int > and Base< other > will be incompatibles. 它会阻止您为动态多态性使用单个基类,因为Base <int>与Base <other>是不兼容的。
One way of handling this is via the visitor pattern . 处理此问题的一种方法是通过访客模式 。 The basic idea is that in your hierarchy of classes you implement an onNode
function that accepts a visitor. 基本思想是,在类的层次结构中,您将实现一个接受访问者的onNode
函数。 Then, you write specific visitors that do what you want. 然后,您编写特定的访问者来执行您想要的操作。 In your case, you'd end up with: 就您而言,您将得到:
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.