Как наследовать определенные переменные из разных классов, унаследованных от одного базового класса?

#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/XOMzDDI8f

2. @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 . Попробуйте мое решение, и если вы можете запустить его в отладчике и пошагово выполнить его.