簡體   English   中英

從(模板)基類內部調用虛擬成員函數

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

當然,如果Tstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM