Как вызвать родительский конструктор не по умолчанию из безымянного производного класса в 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::string& 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" };
Так Adder
правильно создается при запуске программы, и пространство имен защищено от загрязнения.