簡體   English   中英

具有兩個以上類的“隱藏的重載虛擬函數”

[英]“hidden overloaded virtual function” with more than 2 classes

最小示例:

class A {};
class B : public virtual A {};
class C : public virtual B {};

// define two overloading virtual functions
// no inheritance, so no overriding/hiding in this class
struct visitor1
{
    virtual void visit(A& ) {}
    virtual void visit(B& ) {}
    virtual ~visitor1();
};

// covariant types are not allowed for overriding virtuals,
// so the C-visit function would hide A and B, so we add them
// using the "using" keyword
struct visitor2 : public visitor1
{
    using visitor1::visit;
    virtual void visit(C& ) {}
    virtual ~visitor2();
};

// the B-visit is a correct override
// without the use of "using" (or the C-visit) below, the
// compiler warns that the C-visit function from visitor3
// is being overridden
struct visitor3 final : public visitor2
{
    //using visitor2::visit;
    //void visit(C &) override {}
    void visit(B &) override {}
};

編譯:

$ clang++ -Wall -Wextra -Weverything -Wno-c++98-compat visitor.cpp 
visitor.cpp:32:14: warning: 'visitor3::visit' hides overloaded virtual function [-Woverloaded-virtual]
        void visit(B &) override {}
             ^
visitor.cpp:20:22: note: hidden overloaded virtual function 'visitor2::visit' declared here: type mismatch at 1st parameter ('C &' vs 'B &')
        virtual void visit(C& ) {}
                     ^

問題 (假設來自visitor3的評論行保持評論狀態):

  • 為何編譯器會抱怨visitor3::visit(B&)隱藏了visitor2::visit(C&)
  • 它為何抱怨visitor3::visit(B&)是躲在visitor1::visit(A&)什么是不同的在這里)?

附加問題 :如何實現visitor2::visit(C&)visitor1::visit(A&)都未隱藏在visitor3 是否using visitor2::visit; visitor3就足夠了嗎?

visitor3聲明為void visit(B&)聲明或任何名為visit的成員的聲明(可能是int visit;的數據成員) visitor3隱藏了名為visit的父級的任何成員。

在這里,編譯器的警告更多的是好東西。 它認識到一個常見的錯誤模式,該模式包括覆蓋基本的虛擬成員函數而無需照顧重載。 但是它不會檢測到所有隱藏的名稱,也不會對所有隱藏的名稱發出警告。 無論如何,來自visitor1visitor2所有visit都被隱藏。

附加答案 :命名基類成員的using聲明是基類中所有具有該名稱且可見的成員的派生類內的聲明。 因此,這實際上包括那些在基類中也由using聲明聲明的成員。

(使用using聲明聲明的這些成員的行為就像它們是在該類中首先聲明的實際成員一樣。即使重載解析也將其隱含對象參數視為派生類的類型。)

“隱藏”是實際情況的簡寫。 規則很簡單(<g>):查找名稱時,編譯器在當前作用域中啟動; 如果找到該名稱,就完成了。 如果找不到,它將移至下一個封閉范圍。 重復直到完成。

將其與相同作用域中定義的函數之間發生重載的規則結合起來。 編譯器找到該名稱后,同一作用域中的所有定義都將參與重載。 編譯器不會在外部范圍內查找可能與名稱匹配的內容。 那就是瘋狂。

請注意,名稱查找僅查找名稱。 它不取決於找到的名稱是否覆蓋基類中的名稱,也不取決於當前作用域中是否存在多個具有相同名稱的函數(即,該名稱已重載)。 找到名稱后,搜索結束。 該作用域中該名稱的所有定義都參與重載。

因此, visitor3 void visit(B&)在所有基類中隱藏了visit的所有其他定義 名稱是在visitor3定義的,因此編譯器不會在其他地方顯示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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