2015-05-23 10 views
4

Рассмотрите следующие 2 программы.C++: вызов чистой виртуальной функции из функции-члена того же класса

#include <iostream> 
using std::cout; 
class Base { 
    public: 
     virtual void f()=0; 
     void g() { 
      f(); 
     } 
     virtual ~Base() { } 
}; 
class Derived : public Base 
{ 
    public: 
    void f() { 
     cout<<"Derived::f() is called\n"; 
    } 
    ~Derived() {} 
}; 
class Derived1 : public Base 
{ 
    public: 
    void f() { 
     cout<<"Derived1::f() is called\n"; 
    } 
    ~Derived1() { } 
}; 
int main() { 
    Derived1 d; 
    Base& b=d; 
    b.g(); 
    b.f(); 
} 

компилирует & бежит отлично и дает ожидаемый результат ..

#include <iostream> 
using std::cout; 
class Base { 
    public: 
     virtual void f()=0; 
     Base() { 
      f(); // oops,error can't call from ctor & dtor 
     } 
}; 
class Derived : public Base 
{ 
    public: 
     void f() { 
      std::cout<<"Derived::f() is called\n"; 
     } 
}; 
int main() { Derived d; Base& b=d; b.f(); } 

выше программа терпит неудачу в компиляции. Почему разрешено вызывать чистую виртуальную функцию из функции-члена того же класса, в которой объявлена ​​чистая виртуальная функция? Хорошо ли это сделать или это неопределенное поведение, потому что производный класс по-прежнему не обеспечивает реализацию чистой виртуальной функции? Почему нельзя вызывать чистую виртуальную функцию из конструктора & деструктора того же класса? Я знаю, что конструкторы класса Derived могут вызывать чистые виртуальные функции базового класса. Что говорит об этом стандарт C++?

+0

Связанный: http://stackoverflow.com/q/962132/3093378 – vsoftco

+0

@vsoftco: эта ссылка обсуждает разную тему. – Destructor

+0

Второй ответ касается чего-то очень похожего, не то же самое, поэтому я сказал, что это связано. – vsoftco

ответ

5

«Почему чистая виртуальная функция не может быть вызвана из конструктора ...?»

Поскольку конечный класс не строится полностью на данный момент, и vtable не полностью настроить, чтобы правильно направить вызов функции.


Вы можете альтернативно использовать static отношения к основанию и производный класс, как предлагаемый с CRTP:

template<class DerivedType> 
class Base { 
    public: 
     void g() { 
      static_cast<DerivedType*>(this)->f(); 
     } 
     virtual ~Base() { } 
}; 

class Derived : public Base<Derived> 
{ 
    public: 
    void f() { 
     cout<<"Derived::f() is called\n"; 
    } 
    ~Derived() {} 
}; 

class Derived1 : public Base<Derived1> 
{ 
    public: 
    void f() { 
     cout<<"Derived1::f() is called\n"; 
    } 
    ~Derived1() { } 
}; 
+1

Да! И это специально, потому что базовый класс должен быть построен первым. – Christophe

+0

Ницца! Я думаю, вы также можете использовать 'if (dynamic_cast (this)) dynamic_cast (this) -> f();' для безопасности, поскольку он будет ловить 'Base * pBase = new Base ; pBase-> f(); ', что в противном случае даст вам UB. – vsoftco

1

Почему это позволено называть чисто виртуальную функцию из функции члена однополых класс, в котором объявлена ​​чистая виртуальная функция?

Поскольку это технически осуществимо и используется на практике: см. Шаблон метода шаблона.

Почему чисто виртуальная функция не может быть вызвана из конструктора & деструктора одного и того же класса?

Это технически нецелесообразно реализовать на C++ (пока нет таблицы vtable). Но в корне вам это не нужно, так как вы всегда знаете точный класс своего объекта при вызове конструктора.

+0

Это вполне технически выполнимо - и сломан. Это то, что делает Java. –

+0

@ T.C. Отредактировано с учетом вашего комментария. –