C++ частный и защищенный виртуальный метод

Кажется, что хорошо сделать виртуальные методы частными, чтобы разделить интерфейсы для следующих двух клиентов: 1. клиентов, которые создают экземпляр объекта и вызывают метод; 2. клиентов, которые являются производными от класса и могут захотеть переопределить метод. Проще говоря - первый клиент не должен знать, является ли метод виртуальным. Он вызовет открытый невиртуальный метод базового класса, который в свою очередь вызовет приватный виртуальный метод. Смотрите код ниже, например.

Теперь в случае, когда виртуальному методу нужно супер-сообщение соответствующего виртуального метода своего базового класса, такого как, скажем, метод Save - который должен пройти через все виртуальные методы в цепочке наследования, чтобы сохранить данные, соответствующие каждому уровню деривация - у нас нет другого выбора, кроме как использовать защищенный виртуальный метод - если только нет способа гарантировать сохранение данных на всех уровнях деривации без использования супер-сообщений (я не знаю ни одного).

Я хотел бы знать, если выше рассуждения верны.

Убедитесь, что вы используете прокрутку, чтобы увидеть весь код.

#include <iostream>
using namespace std;

class A {

    string data;    

protected:

    virtual void SaveData()= 0;

public:

    A():data("Data of A"){}

    void Save(){
        cout << data << endl;        
        SaveData();
    }
};

class B : public A {

    string data;

protected:

    virtual void SaveData() { cout << data << endl;}

public:

    B():data("Data of B") {}

};

class C : public B {

    string data;
protected:

    virtual void SaveData() {
        B::SaveData();
        cout << data << endl;
    }

public:

    C():data("Data of C") {}
};


int main(int argc, const char * argv[])
{
    C c;
    c.Save();

    return 0;
}

3 ответа

Да, если вам нужно вызвать SaveData другого класса, он должен быть доступен из этого класса - так public или же protected,

Вы совершенно правы

  • NVI (Non-Virtual Interface) требует, чтобы virtual методов не будет public
  • Вызов метода базового класса требует, чтобы он не private

следовательно protected является очевидным решением, по крайней мере, в C++03. К сожалению, это означает, что вы должны доверять разработчику производного класса, чтобы не забыть назвать его "супер".


В C++11 вы можете использовать final предотвратить производный класс от переопределения virtual Способ; это означает, что вы вынуждены ввести новый хук, например:

class Base {
public:
    void save() {
        // do something
        this->saveImpl();
        // do something
    }
private:
    virtual void saveImpl() {}
};

class Child: public Base {
private:
     virtual void saveImpl() final {
         // do something
         this->saveImpl2();
         // do something
     }
     virtual void saveImpl2() {}
};

Конечно, проблема заключается в том, чтобы каждый раз придумывать новое имя... но, по крайней мере, вам гарантировано, что Child::saveImpl будет вызван, потому что никто из его детей не может переопределить его.

Трудно сказать, что вы спрашиваете, но из примера вам не нужно защищать метод. Это на самом деле может быть частным. Подробнее о тонкостях см. Этот пост: в чем смысл частной чисто виртуальной функции?,

Пока вы не вызываете закрытый член из производного класса (или вне классов), все в порядке. Переопределение частных членов в порядке. Это звучит довольно капризно и неправильно, что вы можете переопределить права своих родителей, но в C++ вам разрешено это делать.

Следующее должно быть в порядке:

#include <iostream>
using namespace std;

class A {

    string data;    

private:

    virtual void SaveData()= 0;

public:

    A():data("Data of A"){}

    void Save(){
        cout << data << endl;        
        SaveData();
    }
};

class B : public A {

    string data;

private:

    virtual void SaveData() { cout << data << endl;}

public:

    B():data("Data of B") {}

};
Другие вопросы по тегам