#c #inheritance #multiple-inheritance #diamond-problem
#c #наследование #множественное наследование #алмазная проблема
Вопрос:
Я пытаюсь разобраться в интересной проблеме множественного наследования.
Прародитель — это интерфейсный класс с несколькими методами:
class A
{
public:
virtual int foo() = 0;
virtual int bar() = 0;
};
Тогда есть абстрактные классы, которые частично дополняют этот интерфейс.
class B : public A
{
public:
int foo() { return 0;}
};
class C : public A
{
public:
int bar() { return 1;}
};
Класс, который я хочу использовать, наследуется от обоих родителей и указывает, какой метод должен откуда поступать с помощью директив using:
class D : public B, public C
{
public:
using B::foo;
using C::bar;
};
Когда я пытаюсь создать экземпляр D, я получаю ошибки при попытке создать экземпляр абстрактного класса.
int main()
{
D d; //<-- Error cannot instantiate abstract class.
int test = d.foo();
int test2 = d.bar();
return 0;
}
Может кто-нибудь помочь мне разобраться в проблеме и как наилучшим образом использовать частичные реализации?
Комментарии:
1. В ромбовидном шаблоне вам нужно использовать виртуальное наследование. Но я не верю, что это решит вашу проблему само по себе.
Ответ №1:
У вас нет алмазного наследования. B
И C
базовые классы D
каждого имеют свой собственный A
подобъект базового класса, потому что они практически не наследуются от A
.
Итак, в D
действительно есть четыре чисто виртуальные функции-члена, которые необходимо реализовать: A::foo
и A::bar
из B
и A::foo
и A::bar
из C
.
Вы, вероятно, хотите использовать виртуальное наследование. Объявления классов и списки базовых классов будут выглядеть следующим образом:
class A
class B : public virtual A
class C : public virtual A
class D : public B, public C
Если вы не хотите использовать виртуальное наследование, то вам нужно переопределить две другие чисто виртуальные функции в D
:
class D : public B, public C
{
public:
using B::foo;
using C::bar;
int B::bar() { return 0; }
int C::foo() { return 0; }
};
Ответ №2:
Вам нужно создать свои базовые классы virtual
, чтобы они могли правильно наследоваться. Общее правило заключается в том, что все непубличные функции-члены и базовые классы должны быть virtual
, ЕСЛИ только вы не знаете, что делаете, и не хотите отключить обычное наследование для этого элемента / базы.
Комментарии:
1. «Общее правило заключается в том, что все общедоступные функции-члены и базовые классы должны быть виртуальными» Что? Чье это общее правило? Во всяком случае, общее правило, касающееся виртуальных функций-членов, заключается в том, чтобы сделать их закрытыми и иметь общедоступную невиртуальную функцию-член в базовом классе, вызывающую закрытую виртуальную функцию-член (это обсуждается в статье GotW «Виртуальность» ). Что касается виртуальных базовых классов… Я могу вспомнить только один случай за последние несколько лет, когда мне понадобилось использовать виртуальное наследование.
2. @JamesMcNellis » Я могу вспомнить только один случай за последние несколько лет, когда мне понадобилось использовать виртуальное наследование. » Сколько раз вам нужно использовать номера -виртуальное наследование?
3. @JamesMcNellis: Эта статья в основном полная чушь. Единственное, что получается правильно, это то, что большинство функций-членов (виртуальных или нет) должны быть частными. Наличие общедоступных невиртуальных функций-членов — это ожидаемая катастрофа, которая в основном означает, что класс не может быть подклассом.
4. @ChrisDodd О чем ты говоришь … Чувак, если ты говоришь то, что ты лично думаешь, по крайней мере, не притворяйся, что то, что ты говоришь, является фактом… gtkmm — это всего лишь один из многих примеров классов C , где есть всего несколько виртуальных функций, обычно защищенных, и классы по-прежнему полностью предназначены для подклассов (и они очень легко подразделяются на подклассы). Если вы предпочитаете, чтобы все ваши общедоступные методы были виртуальными — это нормально. Мне это не нравится, но я не буду рассказывать вам, как писать код. Просто не передавайте личные привычки другим людям, как если бы они были фактами…