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

#c #virtual-inheritance

#c #виртуальное наследование

Вопрос:

Рассмотрим следующую программу:

 #include <iostream>
#include <string>

class B
{
public:
    int n;

    B() : n(0) {}
    B(int m) : n(m) {}
};

class D1 : virtual public B
{
public:
    int a;
    
    D1() : a(0) {}
    D1(int m) : a(m) {}
};

class D2 : public D1
{
public:
    int d;
    
    D2() : d(0) {}
    D2(int m) : d(m) {}
    D2(int j, int k) : d(j), D1(k) {}
    D2(int i, int j, int k) : d(i), D1(j), B(k) {}  //Without virtual inheritance,
                                                    //must add new constructor to D1.
};

int main()
{
    std::string s;
    D2 d2(0, 1, 2);
    
    std::cout << "d2.n = " << d2.n << "n";
    std::cout << "d2.a = " << d2.a << "n";
    std::cout << "d2.d = " << d2.d << "n";
    
    std::cout << "Press ENTER to exit.n";
    getline(std::cin, s);
}
 

Наследование D1 виртуально от B позволяет мне вызывать конструктор B из конструктора D2, перепрыгивая через класс D1.

Может ли это использование виртуального наследования отдельно от проблемы наследования алмаза вызывать неопределенное поведение или другой вред?

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

Комментарии:

1. Когда вы говорите «перепрыгивание через класс D1», вы говорите о порядке инициализации? Я подозреваю, что ответ, который вы ищете, зависит от того, что вы подразумеваете под «перепрыгиванием». Построение a D2 построит a B , независимо от того, существует ли виртуальное наследование.

2. Нет, я просто имею в виду, что мне не нужно добавлять в D1 конструктор с двумя аргументами, который вызывал бы конструктор D2 вместо прямого вызова конструктора B.

Ответ №1:

Может ли это использование виртуального наследования отдельно от проблемы наследования алмаза вызывать неопределенное поведение или другой вред?

Виртуальное наследование для любых целей наносит этот «вред»:

  • Доступ к виртуальному базовому классу осуществляется через указатель, что потенциально медленнее
  • Каждый производный класс на всех глубинах должен отвечать за построение виртуальной базы
  • Низведение из виртуальной базы должно выполняться через dynamic_cast . Быстрее static_cast невозможно.

Ваш пример не вводит никакого неопределенного поведения или вреда, которые не существуют для любого другого использования виртуального наследования.