Можно ли вызвать конструктор суперкласса в двух классах от текущего класса в C ++? - PullRequest
6 голосов
/ 11 мая 2011

У меня есть три класса, которые наследуются следующим образом:

Class_A  
Class_B : public Class_A  
Class_C : public Class_B

Class_A содержит конструктор:

public: Class_A(const char *name, int kind);

Class_B не содержит этого конструктора.

В Class_C Я хочу вызвать конструктор Class_A. Что-то вроде:
Class_C(const char *name, int kind) : Class_A::Class_A(name,kind) {}

Проблема в том, что я не могу добавить промежуточный конструктор к Class_B, потому что Class_B - это сгенерированный код, который восстанавливается каждый раз, когда я выполняю очистку. Поэтому я не могу внести какие-либо долгосрочные изменения в Class_B. Излишне говорить, что приведенная выше строка конструктора в Class_C дает error: "type 'Class_A' is not a direct base of ' Class_C '".

Есть ли способ, которым я могу вызвать конструктор Class_A в подклассе Class_C, не требуя такого же типа конструктора в Class_B?

Ответы [ 7 ]

4 голосов
/ 11 мая 2011

Если вы не можете изменить код, который генерирует B, то вам не повезло, AFAIK. Но если класс A содержит такой конструктор, может быть, вам удастся добавить простую функцию-член, которая устанавливает эти две переменные и вызывает ее из конструктора C? Может быть не так эффективно, как это получается, но, по крайней мере, это работает.

1 голос
/ 11 мая 2011

Единственная возможность будет для Class_B фактически наследоваться от Class_A; в этом случае конструктор для Class_A будет вызван из самого производного класса. Но так как это также предполагает изменение генератор кода или вход в генератор кода, вы можете как хорошо измените его, чтобы добавить дополнительный конструктор к Class_B.

Если вы действительно не можете изменить генератор кода или его ввод таким образом, чтобы приведет к созданию дополнительного конструктора, но вы можете измените Class_A и Class_C, тогда есть два возможных решения:

Самый простой - просто использовать отложенную инициализацию; добавить функцию в Class_A, который принимает соответствующие параметры и выполняет инициализация после завершения конструктора. Пока самое простое, этот метод может быть использован только если Class_A может быть сделан для поддержки по умолчанию строительство, и если все члены Class_A поддерживают присваивание с семантикой, такой, чтобы следовала конструкция по умолчанию по присваиванию имеет тот же результат, что и конструкция с использованием аргументов Вы даете (то есть, нет референтных членов, нет не подлежащих обложению членов, нет const членов и т. Д.). В качестве альтернативы, вы можете поставить все функции (или, по крайней мере, члены данных) Class_A в отдельном классе и имеют Class_A производные от этого класса практически. Class_C вызовет Конструктор этого нового класса.
1 голос
/ 11 мая 2011

Вы, вероятно, напичканы (при условии, что вы не можете изменить генерацию класса B), но , если есть какие-то конструкторы для B, которые являются шаблонами, то вы можете специализировать один (для уникальной фиктивной переменной)class) и создайте свой собственный конструктор с любой конструкцией базового класса-A, которую вы считаете ....

В противном случае, хотя и менее эффективный, очевидный, безопасный, чистый подход состоит в использовании A * operator= (если есть), чтобы получить нужное значение ...

C c;
c = A(x, y);

Если эти поля A можно установить только во время строительства, то это более сложная проблема ...

(На мгновение и глубоко войдя в страшную страну Неопределенного поведения, вы можете вызвать деструктор А, а затем поместить его new, но срок жизни А предназначен для охвата Bs и Cs. Практически, очевидный риск состоит в том, что A создал нечто вроде кучи-спределенное значение, на которое B или C уже содержит указатель и может попытаться использовать после того, как деструктор A выпустит его ....)

1 голос
/ 11 мая 2011

Если вы можете сделать базовый класс виртуальным базовым классом, вы можете сделать это, поскольку виртуальные базы всегда должны быть неинициализированы непосредственно во внешнем конструкторе.Если вы не можете изменить то, как ClassB наследует от A, вы всегда можете сделать это:

RealClassA
ClassA : public virtual RealClassA
ClassB : public ClassA
ClassC : public ClassB

Затем в конструкторе ClassC вы можете вызвать RealClassA(...) напрямую.

Обычно это особенность виртуального наследования - это настоящая боль, но она может действительно помочь вам здесь.

0 голосов
/ 11 мая 2011

К языку нельзя получить доступ к непосредственным базовым конструкторам.

Кстати, если Class_A сигнатура конструктора равна,

Class_A(const char *name, int kind);

, тогда Class_B должен иметь некоторый конструкторкоторый будет развлекать конструктор Class_A данного типа.В противном случае это приведет к ошибке компилятора.

Единственный способ избавиться от этой ошибки - предоставить аргументы по умолчанию для Class_A::Class_A(...).

0 голосов
/ 11 мая 2011

Вы можете добавить конструктор для Class_B, который имеет ту же сигнатуру, что и ctor Class_A, и затем позволить Class_C вызвать его в ctor.

Кроме того, список инициализации класса ctor можетне устанавливать значения для членов в базовом классе (независимо от того, являются ли они private protected или public).Вы должны использовать базовый класс ctor для их установки.

0 голосов
/ 11 мая 2011

Если генерируется B, то измените генератор, в противном случае вы обречены.

В зависимости от того, что делает B, может быть решение изменить ваш дизайн, чтобы иметь вывод C из A и B напрямую (если A - ваш класс контейнера, а B - класс обработки).Для этого может потребоваться шаблон B. Если B необходимо воздействовать на членов A, вы все равно можете указать указатель A на конструктор B ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...