Подтвердить что ты не робот

Использование виртуального наследования

Мне нужно написать соглашение о кодировании, которое будет использоваться как новичками, так и опытными разработчиками на С++. Правило о наследовании для динамического полиморфизма выглядит следующим образом:

  • Для динамического полиморфизма рассмотрим использование одиночного наследования (древовидная иерархия), возможно, с множественным наследованием абстрактных интерфейсов
  • для наследования по иерархии (базовые классы и т.д.), по умолчанию, используйте public inheritance
  • для наследования абстрактного интерфейса, по умолчанию, используйте общедоступное виртуальное наследование

За этим правилом последует подробная информация о реализации, возможных исключениях и т.д.

Итак, вопрос: Является ли это правило желательным как для новичков, так и для опытных разработчиков на С++? (плюсы/минусы, а также источники и ссылки приветствуются)


Я вижу:

Плюсы:

  • правило, легко используемое новичками, без ограничения опытных разработчиков.
  • знакомы тем, кто уже знаком с интерфейсами Java/.NET
  • утилит проблемы, связанные с виртуальным наследованием реализации (поскольку он зарезервирован для абстрактных интерфейсов), а также не виртуальное наследование (возможная двусмысленность при кастинге в класс интерфейса)

Минусы:

  • небольшая производительность (скорость при передаче на интерфейс, размер виртуальных таблиц, дополнительные указатели в экземпляре класса)

Примечание. Я прочитал следующие онлайн-источники:

Примечание 2: Использование имени "абстрактного интерфейса" придумано после использования Sutter и Alexandrescu в пункте 36 "Стандарты кодирования С++"


Это один случай, который должен работать (его эквивалент Java/С# с использованием интерфейсов просто работает), но это не в С++, если наследование интерфейса не является виртуальным:

class A
{
   public :
      virtual ~A() = 0 {}
} ;

class B : public A {} ; // should have been virtual to avoid the error
class C : public A {} ; // should have been virtual to avoid the error

class D : public B, public C
{
   public : 
      virtual ~D() {}
} ;

void foo(A * c) {}
void bar(D * d)
{
   foo(d) ; // Error: ambiguous conversions from 'D *' to 'A *
}

И да, явное литье, чтобы удалить двусмысленность, является неправильным решением (явное литье, как правило, является неправильным решением).

4b9b3361

Ответ 1

Знаешь что? Вы уже даете всю важную информацию в вопросе. Я ничего не вижу, чтобы ответить на техническом уровне. И, судя по всему, никто другой не видел серьезных технических проблем с тем, что вы разместили.

Я отвечу на ваш смелый вопрос: Да, он подходит как для новичков, так и для профессионалов.

  • У Newbs есть несколько полезных технических рекомендаций.
  • Плюсы могут делать то, что хотят, если они могут дать обоснование, потому что вы квалифицируете свои правила с помощью "рассмотреть" и "по умолчанию", так что в принципе никто другой не может сказать, что вам нужно сделать это или так из-за правил стиля, потому что фраза ваших правил уже допускает исключения.

Ответ 2

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

Изменить: для записи это рабочий код:

class A
{
public :
    virtual ~A() {}
};

class B : virtual public A {};
class C : virtual public A {};

class D : virtual public B, virtual public C
{
public :
    virtual ~D() {}
};

void foo(A * c) {}
void bar(D * d)
{
    foo(d);
}

int main(void)
{
    D d;
    foo(&d);
    return 0;
}

Ответ 3

Ваше первое правило исключает class D вообще:

Для динамического полиморфизма рассмотрим использование одиночного наследования (древовидная иерархия), возможно с множественным наследованием абстрактных интерфейсов

Ваши правила в порядке.

Итак, каков ваш вопрос? Что осталось сейчас?