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") {}
};