簡體   English   中英

用私有基函數覆蓋公共虛函數?

[英]Override public virtual function with private base function?

讓我們考慮具有以下接口的兩個類AB

class A {
public:
    virtual void start() {} //default implementation does nothing
};

class B {
public:
    void start() {/*do some stuff*/}
};

然后是第三個繼承自兩者的類, A公開,因為它實現了這個“接口”, B私有,因為這是實現細節。

然而,在這個特定的實現中, start()只需要包含對B::start()的調用。 所以我想我可以使用快捷方式並執行以下操作:

class C: public A, private B {
public:
    using B::start;
};

並完成它,但顯然它不起作用。 因此,我無法using私有基函數來覆蓋虛擬。 由此,兩個問題:

  • 有什么方法可以使這項工作像我認為的那樣工作嗎?
  • 為什么編譯器會接受此代碼為有效? 正如我所看到的,現在有兩個start()函數在C具有完全相同的簽名,但編譯器似乎對它很好,並且只調用A::start()

編輯:一些精度:

  • 目標是通過A指針操作C對象。
  • 我目前正在使用一個只調用B::start()的簡單函數,我特別想知道 using 聲明是否確實可以“覆蓋”虛擬,如果不能,如何允許這兩個函數共存。
  • 為簡單起見,我可能省略了一些諸如virtual繼承之類的東西。

是否有任何方法可以使這項工作,因為我認為它可能有效?

你應該覆蓋成員函數並顯式調用B::start()

class C: public A, private B {
public:
    void start() override { B::start(); }
};

為什么編譯器會接受此代碼有效? 正如我所看到的,現在有兩個start()函數在C中具有完全相同的簽名,但編譯器看起來很好並且只調用A::start()

你是對的,有兩個成員函數可以在C( A::start()B::start() )中訪問。 並且在class C ,沒有通過using ...::start()覆蓋start()或使任何基類的start()可見,當嘗試使用unqalified調用成員函數時,將會出現歧義錯誤來自C對象的namelookup。

class A {
public:
    virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
    void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
};

int main(){
    A* a = new C();
    a->start();       //Ok, calls A::start()

    C* c = new C();
    c->start();       //Error, ambiguous         
}

要解決此問題,您必須使用限定名稱,例如:

    C* c = new C();
    c->A::start();       //Ok, calls A::start()

現在,在class C using B::start()只需聲明start()以引用B::start()只要從C的對象使用此名稱即可

class A {
public:
    virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
    void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
public:
     using B::start();
};

int main(){
    A* a = new C();
    a->start();       //Ok, calls A::start()

    C* c = new C();
    c->start();       //Ok, calls B::start()
}

using B::start使函數void B::start()C可見,它不會覆蓋它。 要調用make所有上面的非限定成員函數調用,要調用B::start() ,你應該覆蓋C的成員函數,並使其調用B::start()

class A {
public:
    virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
    void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
public:
    void start() override { B::start(); }
};

int main(){
    A* a = new C();
    a->start();         //Ok, calls C::start() which in turn calls B::start()
                        //    ^^^^^^^^^^^^^^^^ - by virtual dispatch

    C* c = new C();
    c->start();         //Ok, calls C::start() which in turn calls B::start()

}

我想你可能會混淆“公共”和“私人”的含義。 在C ++繼承上下文中,這僅僅意味着一切都知道'C'是'A',而對於'B'類型,只有其他'C'對象可以訪問'C'對象的父方法('B'方法) 。

第二部分是關於繼承歧義。 using B::start; 繼承確實是模糊的,不會編譯(當轉到c.start() ),所以實際上在你的例子中添加該語句不是可選的(使用A或B),如果你不想經常使用合格的路徑。

我不清楚你是否期望c()->start(); 調用'A'方法或'B'方法,但using語句將根據您的需要確定它。 你編寫代碼的方式有點不確定 - “A” 真的需要開始嗎?

暫無
暫無

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

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