Виртуальная функция в частном или защищенном наследовании

Легко понять виртуальную функцию в публичном наследовании. Итак, какова точка для виртуальной функции в частном или защищенном наследовании?

Например:

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 уничтожает все концептуальные связи между производным и базовым классом. Производный класс просто реализуется в терминах базового класса, не более того. Частное наследование - это всего лишь метод реализации и не подразумевает никакой связи между участвующими классами.