#c #inheritance #constructor #default-constructor #unnamed-class
#c #наследование #конструктор #конструктор по умолчанию #неназванный класс
Вопрос:
В C структуры и классы одноразового использования могут быть объявлены безымянными, если объект создается напрямую:
struct { int x; int y; } point;
Неназванные классы также могут наследовать от базового класса. Это, например, полезно для создания списка различных «процессоров» из интерфейса базового процессора. Вот простой пример:
struct Processor {virtual int op(int a, int b) = 0;};
struct : Processor {int op(int a, int b) override { return a b; }} Adder;
struct : Processor {int op(int a, int b) override { return a*b; }} Multiplier;
Таким образом, оба Adder
и Multiplier
становятся отдельными производными объектами Processor
интерфейса. Но что, если базовый процессор имеет большую структуру и имеет конструктор, который требует параметров? Давайте посмотрим на этот пример:
class Processor {
private:
std::string name;
public:
virtual int op(int a, int b) = 0;
const std::stringamp; getName() const { return name; }
Processor(std::string name) : name(name) {}
};
Как создать неназванный подкласс для этого процессора, например «Сумматор». Наивная попытка:
class : public Processor {
public:
int op(int a, int b) override { return a b; }
} Adder { "Adder" };
к сожалению, сбой, потому что у неназванного класса нет неявно сгенерированного конструктора, который принимал бы "Adder"
в качестве своего аргумента. И явное объявление такого конструктора также невозможно, потому что невозможно объявлять конструкторы в неназванных классах: конструктор называется так же, как класс, но если нет имени класса, то нет и имени конструктора.
Я знаю, что существуют простые обходные пути: один из них — все-таки дать имя (потенциально в пространстве имен), а затем использовать это для объявления конструктора. Также может возникнуть соблазн использовать виртуальный init()
метод, который вызывается из конструктора Processor
и который выполняет работу, которую должен выполнять конструктор. Но это не работает, так как виртуальный вызов в конструкторе пока не достигает метода в производном классе. Но вместо этого вызов init()
может быть скрыт в инициализаторе элемента данных неназванного класса.
Но есть ли какой-либо «чистый» ответ C , который сохраняет неназванный класс неназванным и по-прежнему выполняет в конструкторе все, что должно быть сделано в конструкторе?
Ответ №1:
При написании этого вопроса я уже нашел ответ, поэтому поделюсь им здесь: С C 11 using
ключевое слово было расширено, чтобы разрешить явный импорт конструкторов базового класса, и это аккуратно решает проблему:
class : public Processor {
using Processor::Processor;
public:
int op(int a, int b) override { return a b; }
} Adder { "Adder" };
So Adder
создается правильно при запуске программы, и пространство имен защищено от загрязнения.