2017-03-20 14 views
8

Kilka dni temu chciałem zanurkować w świecie C++. Studiuję podstawowe i pochodne koncepcje klas. Czy ktoś mógłby wytłumaczyć niuanse z następującymi dwoma fragmentami kodu?Podstawowe i pochodne klasy C++

class A 
{ 
    private: 
    virtual int GetValue() { return 10; } 

    public: 
    int Calculate() { return GetValue()*1.5; } 
}; 

class B: public A 
{ 
    private: 
    virtual int GetValue() { return 20; } 
}; 

int main() 
{ 
    B b; 
    std::cout << b.Calculate() << std::endl; 

    return 0; 
} 

Wyjście jest 30, ale 15 oczekiwano

class A 
{ 
    private: 
    int m_data; 

    public: 
    A(): m_data(GetValue()) {} 
    int Calculate() { return m_data*1.5; } 
    virtual int GetValue() { return 10; } 
}; 

class B: public A 
{ 
    public: 
    virtual int GetValue() { return 20; } 
}; 

int main() 
{ 
    B b; A* ap; 
    ap=&b; 
    std::cout << ap->Calculate() << std::endl; 

    return 0; 
} 

Wyjście jest 15, ale 30 oczekiwano

Może ktoś wyjaśnić i pomóc mi zrozumieć rozumowanie? Coś jest nie tak z moim myśleniem o tej koncepcji, ale nie jestem w stanie tego rozgryźć.

+2

Wyjaśnij, dlaczego myślałeś, że twój kod poda te wartości. –

Odpowiedz

5

Pierwszy przypadek:

To jest trywialne. Masz instancję instancji B, a użytkownik oblicza return GetValue() * 1.5;, który używa B::GetValue(), ponieważ został oznaczony jako GetValue() na virtual w klasie bazowej. Dlatego oceniano 20 * 1,5.

Drugi przypadek:

Nie tak banalny. Wywołujesz GetValue() w inicjatorze elementu podstawowego, aby ustawić wartość dla m_data. Standardowe C++ wymaga, aby w tym przypadku wywoływana była metoda klasy bazowej GetValue(). (Nieformalnie uważam, że jest to spowodowane tym, że klasa B nie jest konstruowana, dopóki klasa A nie zostanie w pełni skonstruowana). W związku z tym oceniono 10 * 1,5. Co ciekawe, jeżeli GetValue() byłby czystym wirtualnym, wówczas zachowanie programu byłoby niezdefiniowane.


referencyjny: Why a virtual call to a pure virtual function from a constructor is UB and a call to a non-pure virtual function is allowed by the Standard?

+1

Twoja odpowiedź jest bardzo pomocna, zrozumiała i kompletna. Bardzo ważne było dla mnie zrozumienie tego przed rozpoczęciem kursu. Dziękuję bardzo. Mam to teraz. – Zizou23

2

Wypróbuj poniższy kod na drugi przykład:

class A 
{ 
private: 
int m_data; 

public: 
A(): m_data(GetValue()) { std::cout << "Init m_data and A ";} 
int Calculate() { return m_data*1.5; } 
virtual int GetValue() { std::cout << "GetValue from A ";return 10; } 
}; 

class B: public A 
{ 
public: 
B() { std::cout << "Init B "; } 
virtual int GetValue() { std::cout << "GetValue from B"; return 20; } 
}; 

int main() 
{ 
B b; A* ap; 
ap=&b; 
std::cout << ap->Calculate() << std::endl; 

return 0; 
} 

To jest taka sama jak już masz ale z wyjściami. Powinieneś uzyskać GetValue from A Init m_data and A Init B 15. Mam nadzieję, że teraz widzisz, dlaczego masz wydajność 15. Przy wyjściach powinieneś być w stanie zrekonstruować kolejność wykonania.

Powiązane problemy