2012-09-26 24 views
6

Mam więc abstrakcyjną klasę bazową bez abstrakcyjnych metod. W celu egzekwowania abstrakcyjność, mam ogłoszony (nietrywialne) destruktora jako czysto wirtualne:Czyste wirtualne dziedziczenie, wielokrotne dziedziczenie i C4505

class AbstractClass 
{ 
public: 
    AbstractClass() 
    { 
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl; 
    } 
    virtual ~AbstractClass() = 0 
    { 
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl; 
    } 
}; 

class ConcreteClass : public AbstractClass 
{ 
public: 
    ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl; 
    } 
    virtual ~ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl; 
    } 
}; 

To buduje i działa zgodnie z oczekiwaniami; wyjście do bloku kodu, który po prostu wyznacza wystąpienie ConcreteClass jest

 

    AbstractClass::AbstractClass() 
    ConcreteClass::ConcreteClass() 
    ConcreteClass::~ConcreteClass() 
    AbstractClass::~AbstractClass() 

Teraz, kiedy ma pochodzić AbstractClass z innej klasy stosowanych jako klasy interfejsu sam mający (trywialne) destructor wirtualna (czystą lub w inny sposób) , to nadal działa:

class IAlpha 
{ 
public: 
    virtual ~IAlpha() = 0 {} 
}; 

class AbstractClass : public IAlpha 
{ 
public: 
    AbstractClass() 
    { 
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl; 
    } 
    virtual ~AbstractClass() = 0 
    { 
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl; 
    } 
}; 

class ConcreteClass : public AbstractClass 
{ 
public: 
    ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl; 
    } 
    virtual ~ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl; 
    } 
}; 

problem pojawia się, gdy próbuję wdrożyć dwa różne interfejsy w ten sposób:

class IAlpha 
{ 
public: 
    virtual ~IAlpha() = 0 {} 
}; 

class IBeta 
{ 
public: 
    virtual ~IBeta() = 0 {} 
}; 

class AbstractClass : public IAlpha, public IBeta 
{ 
public: 
    AbstractClass() 
    { 
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl; 
    } 
    virtual ~AbstractClass() = 0 
    { 
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl; 
    } 
}; 

class ConcreteClass : public AbstractClass 
{ 
public: 
    ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl; 
    } 
    virtual ~ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl; 
    } 
}; 

w tym momencie, kiedy bu ilding, otrzymuję następujące ostrzeżenie:

warning C4505: 'AbstractClass::~AbstractClass' : 
unreferenced local function has been removed

O dziwo jednak, wyjście nadal pokazuje AbstractClass::~AbstractClass() nazywa uzyskiwanie.

Czy to błąd w MSVC9 (VS 2008)? Czy mogę bezpiecznie zignorować to ostrzeżenie?

Edycja: Próbowałem oddzielić definicje czystych wirtualnych metod od definicji klasy, ponieważ najwyraźniej składnia = 0 {} jest nieprawidłowa. Niestety nadal pojawia się C4505, czy określam inline czy nie.

Ponieważ nie znalazłem sposobu na ostrzeżenie dla tych metod (ostrzeżenie zostanie wywołane z innych części kodu), być może trzeba będzie usunąć czysty wirtualny specyfikator z AbstractClass i polegać na tworzeniu konstruktorów chroniony. Nie jest to idealne rozwiązanie, ale przebije rearchitekcję hierarchii klas, aby obejść błędne ostrzeżenie.

Odpowiedz

0

Czy próbowałeś zdefiniować destruktory w sposób nieliniowy? Być może ostrzeżenie jest z tym związane.

Takich jak this code.

+0

Próbowałem kod w linku; dostaje to samo ostrzeżenie, mimo że, jak poprzednio, działa poprawnie po uruchomieniu. – somethingdotjunk

0

Kod nie powinien się kompilować. Wewnątrz definicji klasy nie można definiować czystych wirtualnych funkcji. Przenieś definicję poza klasy:

struct IAlpha { 
    virtual ~IAlpha() = 0; 
}; 
inline IAlpha::~IAlpha() {} 
// similarly for the rest. 

Poza tym kod jest poprawny i powinien się skompilować.

+0

Interesujące; Nie wiedziałem, że nie można połączyć czystego wirtualnego specyfikatora i treści metody. Niestety, wypróbowałem to również w ten sposób i nadal pojawia się ostrzeżenie (patrz odpowiedź od jeffmagill). – somethingdotjunk

3

To jest błąd w MSVC++ 2010 i wcześniejszych. Kod faktycznie otrzymuje numer , mimo że kompilator twierdzi, że usunął kod. Wydaje się być poprawiony w MSVC++ 2012. Inne kompilatory takie jak gcc lub clang nie emitują ostrzeżenia. Składnia "... = 0 {...}" jest niezgodna z normą zgodnie ze standardem C++ 03 sekcja 10.4.2 (choć MSVC++ nie narzekać), jak to już zauważył:

Uwaga: deklaracja funkcji nie może zapewnić zarówno czystej specyfikator i definicję

jednak zdefiniowanie czysta wirtualny destruktor ogólnie nie jest nielegalny, a rozdział 12.4.7 stwierdza:

Niszczyciel może być ogłoszony wirtualny (10.3) lub czysty wirtualny (10.4); Jeśli w obiekcie zostaną utworzone jakiekolwiek obiekty tej klasy lub klasy pochodnej, to zostanie zdefiniowany destruktor. Jeśli klasa ma klasę podstawową z wirtualnym destruktorem, jej destruktor (bez względu na to, czy użytkownik lub użytkownik jest domyślnie zadeklarowany) jest wirtualny.

Mój sposób wyłączyć ostrzeżenie jest dodać następujące wiersze do nagłówka:

#if defined(_MSC_VER) && (_MSC_VER <= 1600) 
# pragma warning(disable:4505) 
#endif 

Jeśli chcesz bardziej lokalnie wyłączyć ostrzeżenia następnie #pragma warning(push) i #pragma warning(pop) może być pomocne. Patrz: http://msdn.microsoft.com/en-us/library/2c8f766e(v=vs.80).aspx

Ponieważ kod wydaje się być wywoływany, możesz zignorować ostrzeżenia w mojej opinii.

+0

Chciałbym wiedzieć, skąd ten błąd został zgłoszony, więc mogę go przytoczyć. – chappjc

0

Nie można zdefiniować funkcji wirtualnej jako wbudowanej.

Ponieważ inline jest w kompilacji. Wirtualny jest w środowisku wykonawczym.