[英]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.