Виртуальная функция в частном или защищенном наследовании
Легко понять виртуальную функцию в публичном наследовании. Итак, какова точка для виртуальной функции в частном или защищенном наследовании?
Например:
class Base {
public:
virtual void f() { cout<<"Base::f()"<<endl;}
};
class Derived: private Base {
public:
void f() { cout<<"Derived::f()"<<endl;}
};
Это все еще называется переопределением? Какое использование этого случая? Какая связь этих двух f()?
Спасибо!
Ответы
Ответ 1
Частное наследование - это всего лишь метод реализации, а не отношения is-a, как объясняет Скотт Майерс в Effective С++:
class Timer {
public:
explicit Timer(int tickFrequency);
virtual void onTick() const; // automatically called for each tick
...
};
class Widget: private Timer {
private:
virtual void onTick() const; // look at Widget private data
...
};
Клиенты Widget не могут вызывать onTick на виджете, потому что это не часть концептуального интерфейса Widget.
Ответ 2
Ваш метод f()
по-прежнему отменяется. Эта связь полезна при реализации шаблона дизайна Template Method. В принципе, вы бы реализовали общие наборы операций в базовом классе. Затем эти операции с базовым классом вызывают виртуальный метод, например ваш f()
. Если производный класс переопределяет f()
, операции базового класса заканчиваются вызовом производной версии f()
. Это позволяет производным классам поддерживать базовый алгоритм таким же, но изменять поведение в соответствии с их потребностями. Здесь тривиальный пример:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f() { cout<<"Base::f()" << endl; }
protected:
void base_foo() { f(); }
};
class DerivedOne: private Base
{
public:
void f() { cout << "Derived::f()" << endl;}
void foo() { base_foo(); }
};
class DerivedTwo: private Base
{
public:
void foo() { base_foo(); }
};
int main()
{
DerivedOne d1;
d1.foo();
DerivedTwo d2;
d2.foo();
}
Здесь результат во время выполнения:
$ ./a.out
Derived::f()
Base::f()
Оба производных класса называют одну и ту же операцию базового класса, но поведение для каждого производного класса различно.
Ответ 3
- Не нужно указывать на каждую комбинацию различных функций. Вам просто разрешено комбинировать их.
- Виртуальный защищенный член доступен для производных классов, поэтому он им полезен.
- Виртуальный частный член доступен для классов друзей, поэтому он им полезен.
Ответ 4
Пример:
/// Thread body interface
class runnable
{
public:
virtual ~runnable() {}
virtual void run() =0;
};
/// Starts OS thread, calls p->run() in new thread
thread_id start_thread( runnable* p );
/// Has a private thread
class actor: private runnable, private noncopyable
{
private:
thread_id tid; /// private thread
public:
actor() { tid = start_thread( this ); } // here this IS-A runnable
// ...
virtual ~actor() { stop_thread( tid ); }
private:
virtual void run() { /* work */ }
};
Ответ 5
Как личное, так и защищенное наследование позволяет переопределять виртуальные функции в частном/защищенном базовом классе, и ни одно из утверждений, которое является производным, не является своего рода базой.
Защищенное наследование позволяет производным классам производных классов знать о соотношении наследования и по-прежнему переопределять виртуальные функции.
Частное наследование класса Base
в вашем классе Derived
уничтожает все концептуальные связи между производным и базовым классом. Производный класс просто реализуется в терминах базового класса, не более того. Частное наследование - это всего лишь метод реализации и не подразумевает никакой связи между участвующими классами.