#c #class #inheritance
#c #класс #наследование
Вопрос:
У меня есть базовый класс A, 2 дочерних класса B и C, которые оба наследуются от A, и у меня есть класс D, который наследуется как от B, так и от C, в котором я хочу взять _a из B и _b из C без необходимости выполнять виртуальный метод для print_a и print_b, если это возможно
# include <iostream>
class A
{
public:
A(void) : { }
~A(void) { }
inline void print_a(void) { std::cout << _a << std::endl; }
inline void print_b(void) { std::cout << _b << std::endl; }
protected:
int _a;
int _b;
};
class B : virtual A
{
public:
B(int a) : A() { _a = a, _b = 0; }
~B(void) { }
protected:
using A::_a;
using A::_b;
};
class C : virtual A
{
public:
C(int b) : A() { _a = 0, _b = b; }
~C(void) { }
protected:
using A::_a;
using A::_b;
};
class D : virtual public A, private B, private C
{
public:
D(void) : A(), B(5), C(5) { }
~D(void) { }
private:
using B::_a;
using C::_b;
};
int main(void)
{
D foo;
foo.print_a();
foo.print_b();
return (0);
}
Мой общий класс наследует методы print_a и print_b от A, и я хочу, чтобы он наследовал _a = 5 от B и _b = 5 от C, но он не работает, он выводит:
0
5
Вместо:
5
5
Комментарии:
1. Вы можете исправить это, изменив определение D на
class D : virtual public A, private C, private B
, но вы играете с огнем, если переупорядочивание вещей изменяет результат. Вот пример с этим изменением: onlinegdb.com/XOMzDDI8f2. @JerryJeremiah Это моя ошибка, я написал { _a = a, _b = 5; } вместо { _a = a, _b = 5; } , что я хочу сделать, это скопировать элемент B ::_a в D::_a и C::_b в D::_b
Ответ №1:
Поскольку вы используете virtual
для всех базовых классов, в итоге у вас D
будет только один A
(а не один как базовый D
, один как базовый B
и один как базовый C
).
Проблема в ваших конструкторах.
Конструктор производного класса вызывает конструкторы всех базовых классов в том порядке, в котором они указаны в списке базовых классов, поэтому в вашем случае D::D
вызывает:
A::A() -> _a and _b uninitialized
B::B(5)
_a = 5
_b = 0
C::C(5)
_a = 0
_b = 5
Непонятно, почему вы устанавливаете _a
and _b
несколько раз в разных конструкторах. Было бы лучше инициализировать элементы в списке инициализаторов элементов конструктора, а не назначать его в теле конструктора. Вы могли бы, например, написать
A(int a, int b) : _a(a), _b(b) {}
B(int a) : A(a, 0) {}
C(int b) : A(0, b) {}
D() : A(5, 5), B(5), C(5) {}
Это D::D()
приведет к
A(5, 5) -> _a initialized to 5, _b initialized to 5
B(5) -> no effect (on A/_a/_b)
C(5) -> no effect (on A/_a/_b)
Если вы хотите придерживаться своего дизайна и инициализировать переменные в телах конструктора, вы можете просто добавить код D::D
, чтобы перезаписать все, что задают конструкторы базового класса:
D() : A(), B(5), C(5) { _a=5; _b=5; }
Комментарии:
1. РЕДАКТИРОВАТЬ: конструктор B равен _a = 5, _b = 0, вместо b = 5, чтобы брать только _a из b и _b из c
2. Хорошо, тогда как я могу наследовать _a от B и _b от C без вызова конструкторов B и C? Это вызывает синтаксическую ошибку
3. Вы не можете наследовать от части A, только от полного A. В чем именно заключается ваша основная проблема? Чего вы хотите достичь? В чем проблема с подходом, на который я подписался? Также вы, кажется, неправильно понимаете, нет _a из B и _b из C, есть только один A с _a и _b .
4. Что я хотел сделать, так это иметь, например, класс Human, с 2 дочерними элементами Warrior и Thief, для которых, например, для переменной health было бы установлено значение 100 для warrior и 80 для thief, а для переменной speed установлено значение 10 для thief и 5 для warrior, а затем я хочу создать классСупервоин, у которого было бы здоровье воина и скорость вора, вот почему я не могу инициализировать _a и _b в базовом классе
5. Хорошо, это дает мне хорошее понимание, спасибо. В этом случае мое предложенное решение будет работать. Важной частью является то, что вы не выполняете присваивания _a и _b в конструкторах B и C, вам нужно инициализировать _a и _b
A::A
. Попробуйте мое решение, и если вы можете запустить его в отладчике и пошагово выполнить его.