2015-06-23 10 views
5

Załóżmy, że mam dwie klasy bazowe B1 i B2 i klasy D który wynika zarówno z B1 i B2 w następujący sposób:Jak zastąpić funkcje wirtualne klas bazowych, które mają identyczne nazwy w dziedziczeniu wielokrotnym?

class B1 { 
public: 
    // ... 
    virtual void foo() final { cout << "Hello, B1\n"; } 
}; 

class B2 { 
public: 
    // ... 
    virtual void foo() { cout << "Good riddance, B2!\n"; } 
}; 

class D :public B1, public B2 { 
    // ... 
}; 

Projektując klasę D, chcę zastąpić funkcję składową o nazwie foo() z B2 ; jednak foo() w B1 jest oznaczony jako final i uniemożliwia mi nadpisanie w B2 B2 foo(). Jakie jest najlepsze podejście do zastąpienia foo() z B2?

+0

nie mówi funkcją jest wirtualny, a ostateczna zaprzeczając sobie? Po prostu ciekawy: P – Ediac

+0

@Ediac, 'B1' może mieć klasę podstawową, która definiuje' foo' jako wirtualną. W takim przypadku '' foo' jest wirtualne, niezależnie od tego, czy jest zaznaczone w ten czy inny sposób. – chris

+0

Aby uniknąć tego zamieszania, dziedziczenie wielokrotne jest niedozwolone w językach takich jak Java i C# – SabaRish

Odpowiedz

8

Nie sądzę, że to, co chcesz zrobić, jest możliwe w sposób pokazany w pytaniu. Z N3337, §10.3/2 [class.virtual]

Jeżeli wirtualne funkcja element vf deklaruje klasą Base w klasie Derived, pochodzący, bezpośrednio lub pośrednio, z Base, funkcję członu vf z podana jest ta sama nazwa, lista parametrów (8.3.5), kwalifikacja cv i kwalifikator (lub brak tego samego), co Base::vf, następnie Derived::vf jest również wirtualny (niezależnie od tego, czy jest tak zadeklarowany), a także zastępuje Base::vf. ...

D::foo dopasowuje wszystkie te kryteria B1::foo i B2::foo, dlatego zastępuje zarówno. A ponieważ B1::foo to final, kod jest źle sformułowany.

Jednym z rozwiązań jest wprowadzenie dodatkowego poziomu dziedziczenia. Zdefiniuj klasę, na przykład D2, która pochodzi od B2 i zastępuje B2::foo. Wtedy D może pochodzić z B1 i D2.

class D2 : public B2{ 
public: 
    virtual void foo() override { cout << __PRETTY_FUNCTION__ << '\n'; } 
}; 

class D :public B1, public D2 
{}; 

D d; 
// d.foo(); // error - ambiguous 

D2& d2 = d; 
d2.foo(); // calls D2::foo 
B2& b2 = d; 
b2.foo(); // calls D2::foo 

B1& b1 = d; 
b1.foo(); // calls B1::foo 

Live demo

+0

Podoba mi się twoje rozwiązanie, odpowiada na pytanie, jakie mu podałem. Nie odbiegając zbytnio od tego tematu, ale w sensie projektowym, to rozwiązanie faktycznie zakopałoby ten mały problem, ponieważ hierarchia rośnie, a problem pozostałby, gdyby ktoś chciał zastąpić 'foo()' z 'D' lub jakiegokolwiek innego. z pod-klas D. Zastanawiam się, czy może istnieć lepsze rozwiązanie, które może pozwolić na dalsze (i potencjalnie bezpieczne) wyprowadzenia z wykorzystaniem D jako podstawy. – Region

+0

@Region Masz rację, że to rozwiązanie po prostu kopie puszkę w dół drogi, jeśli chcesz czerpać z 'D' i przesłonić' foo', znów masz ten sam problem. Niestety, nie widzę sposobu na obejście tego. Właśnie znalazłem [tę odpowiedź] (https://stackoverflow.com/a/18400950/241631) na podobne pytanie, co sugeruje to samo obejście, co ja.Może powinieneś zamieścić inne pytanie, łącząc się z tym i poprosić o alternatywne rozwiązanie. – Praetorian

Powiązane problemy