2015-07-22 5 views
5

W artykule MSDN na ostrzeżenie C4673 zawiera ten przykład, który emituje ostrzeżenie z konkretnym komunikatem:Zrozumienie C4673 kompilator ostrzeżenie

Base: this base class is inaccessible 
// C4673.cpp 
// compile with: /EHsc /W4 
class Base { 
private: 
    char * m_chr; 
public: 
    Base() { 
     m_chr = 0; 
    } 

    ~Base() { 
     if(m_chr) 
     delete m_chr; 
    } 
}; 

class Derv : private Base { 
public: 
    Derv() {} 
    ~Derv() {} 
}; 

int main() { 
    try { 
     Derv D1; 
     // delete previous line, uncomment the next line to resolve 
     // Base D1; 
     throw D1; // C4673 
    } 

    catch(...) {} 
} 

Niestety, artykuł MSDN nie daje żadnych wyjaśnień problem. Nie rozumiem, co jest nie tak z powyższym kodem. Dlaczego daje ostrzeżenie? Jest to zestaw narzędzi MSVC 2013-1102.

+2

Trudno zaoferować żadnych sugestii, nie widząc kodu – Petr

+0

@Petr: jak już wspomniałem, kod znajduje się w artykule MSDN. Wkleję to tutaj. –

+1

Proponuję przeformułowanie twojego pytania na "Nie rozumiem przykładu na ..." i nie wspominam o twoim kodzie. – Petr

Odpowiedz

5

mogę odtworzyć to na webcompiler i pełny tekst ostrzeżenia jest:

main.cpp (28): Ostrzeżenie C4673: „rzucanie” Derv następujące typy nie będą rozpatrywane w miejscu połowu
main.cpp (28): ostrzeżenie C4670: 'Base': ta klasa bazowa jest niedostępne

to prawda. Gdybyśmy mieli:

try { 
    throw Derv(); 
} 
catch (Base&) { 
    std::cout << "I caught it!"; 
} 

To nie będzie pasować do obsługi wyjątku Derv, ponieważ Derv dziedziczy prywatnie z Base i tak, że klasa bazowa jest niedostępny. W tym przykładzie wyjątek byłby nieprzechwycony.

Jednak to dziwne ostrzeżenie emitować jak w przykładzie MSDN, wyjątek zostanie złapany z:

catch(...) {} 

Wygląda więc na to, że ostrzeżenie nie faktycznie sprawdzić na wszystko - to tylko ogólny -powtarzanie ostrzeżenia, że ​​możesz robić coś szkodliwego, bez faktycznego sprawdzania, czy jesteś, czy nie. To nie wydaje mi się szczególnie przydatnym ostrzeżeniem. Jeśli złapaliśmy się przez Base&, tak - powiedz mi, że tak się nie stanie - ale łapiemy przez ....

+0

Tak to właśnie jest! Dziedziczenie prywatne! Nie zauważyłem. Zmiana tego na publiczną rozwiązuje problem. –

+1

... i dodając, że 'catch (Base &)' w przykładzie, lub nawet * pomijając * 'catch (...)', uczyniłoby to kryształowo jasne, o czym jest ostrzeżenie. Kolejny z tych klejnotów MS ... – DevSolar

+0

Ostrzeżenie o 'catch (Base &)' nie będzie poprawne. Załóżmy, że istnieje jednostka tłumaczeniowa, która zawiera definicję Base, ale nie Derv. Kompilator nie wiedziałby, że Derv dziedziczy prywatnie z bazy, więc nie będzie mógł wydać ostrzeżenia. – user1610015

3

Oto bardziej ograniczonej przykład:

class Base { public: virtual ~Base() {} }; 

class Derived : private Base {}; 

int main() 
{ 
    Derived d; 
    throw d; // C4673 
} 

Problemem jest to, że programista może napisać throw oświadczenie takiego jak część każdej funkcji, a następnie oczekiwać wynikowy wyjątek być złapany polimorficznie jako Base . To nie zadziała, ponieważ dziedziczenie to private. Musisz złapać Derived lub ....

Powodem, dla którego odpowiednie ostrzeżenie jest odpowiednie, jest to, że nie tylko każdy obiekt ma nie tylko throw. Zwykle istnieją określone typy wyjątków, które są używane tylko do tego. Nie ma sensu używać prywatnego dziedziczenia dla takich typów wyjątków. Po prostu wprowadzi to mylące zachowanie, ale nie ma przypadków rzeczywistego użycia.

Niestety jedynym miejscem, w którym możemy wykryć, czy klasa jest typem wyjątku, jest throw, więc to jedyne miejsce, w którym możemy wygenerować to ostrzeżenie.