[英]Calling a virtual member function from inside the (template) base class
假設我有以下內容:
#include <iostream>
#include <string>
template<class T>
class base
{
public:
void print()
{
T t = get();
std::cout << t << std::endl;
}
virtual T get() const
{
// assumes T can be constructed from, say, -1
T t = -1.0;
return t;
}
};
class derived : public base<std::string>
{
public:
virtual std::string get() const
{
// this is a silly example, but one can
// imagine that what we return here could
// depend on data members of derived
return "this is a string";
}
};
int main()
{
derived d;
d.print();
return 0;
}
在我看來, d.print()
應該調用derived::get()
因為get()
是虛擬的。 但是,我收到編譯器錯誤,說我無法將string
初始化為-1.0
,這意味着當我調用d.print()
時,編譯器正在嘗試調用base::get()
d.print()
。 這是怎么回事?
但是,我收到編譯器錯誤,說我無法將字符串初始化為-1.0,這意味着當我調用d.print()時,編譯器正在嘗試調用base :: get()。
不,編譯器錯誤意味着編譯器正在嘗試實例化base<std::string>::get()
,它必須這樣做,因為derived
使用base<std::string>
作為基類。 僅僅因為你沒有調用函數並不意味着你不能 。 你仍然可以直接調用base<std::string>::get()
。
您實例化了base<std::string>
並將其用作基類。 由於base<std::string>::get()
是一個虛函數,因此使用base<std::string>
作為基類這一事實將其視為“使用”。 由於它正在使用中,因此必須進行實例化。 因此編譯器必須並將嘗試編譯該函數。
由於std::string
不能從float中隱式構造,因此編譯器會因失敗的模板替換而出錯。
當您隱式實例化一個類模板,僅使用這些成員函數將被實例化,因為你已經知道了,否則你就不會問這個。 問題是標准中的使用定義可能不完全符合您的預期,特別是,如果它不是純粹的話,任何虛函數都會被使用
§3.2p2[...]如果虛擬成員函數不純,則使用它是有用的。[...]
這意味着即使您的代碼沒有顯式調用它也會使用base::get
,因此編譯器將隱式實例化它並觸發您看到的編譯器錯誤。
T t = -1.0;
當然,如果T
是std::string
,這將無法編譯。 它與get
virtual
無關,在運行時將調用哪個函數。 運行時在代碼編譯為機器代碼后出現,您的代碼甚至無法編譯。
你為什么不這樣做:
T t = T();
同樣,它需要T
具有默認構造函數。
問題出在這個方法中(其中T = std :: string):
virtual T get() const
{
// assumes T can be constructed from, say, -1
T t = -1.0;
return t;
}
編譯器是對的。 您不能使用double值初始化std :: string。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.