[英]Accessing derived class method from base class method without virtual functions on run time
[英]Accessing a method from a templated derived class without using virtual functions in c++?
我该如何解决? 我显然不能使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'
这个说法:
int v = b->value();
变量'b'被当作Derived <int>的对象进行处理。
因此,告诉编译器:
int v = dynamic_cast<Derived<int>*>(b)->value();
注意:如果b不是Derived <int>,则强制转换的结果为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);
}
我认为,如果您问这个问题(根据我的经验和我的设计),您的设计可能会有一些问题。
但是,有一些解决方法:
但是,这里真正的问题是您试图在这里描述什么? Base,Derived和value()的含义是什么。 问自己这些问题,您可能不需要这些答案...
一些解决方案:
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;
}
在这种情况下,Base需要了解模板类型,因此b-> value返回T。
我建议将模板添加到Base,然后在Base上使值成为虚拟函数
您可以将指针投射到Derived
:
int v = dynamic_cast<Derived<int>*>(b)->value();
当然,在实际代码中,您必须添加检查以确保dynamic_cast
不会失败。
为什么也不要使基于Base模板的类呢? 然后,您可以作为虚拟成员而有价值。
或者,您可以将b降为Derived。
看起来您想要动态多态性,但仅使用模板的“静态多态性”。
如果要动态多态性,则确实需要基类中的虚拟成员(以及虚拟析构函数),或者如果没有通用接口,则需要down_cast。
如果没有,请删除虚拟析构函数,并仅使用指向派生类型的指针或实例。
关于Base作为模板:
它会阻止您为动态多态性使用单个基类,因为Base <int>与Base <other>是不兼容的。
处理此问题的一种方法是通过访客模式 。 基本思想是,在类的层次结构中,您将实现一个接受访问者的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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.