2015-08-06 4 views
3

Мне нужно использовать классы интерфейса C++ для реализации неуправляемой библиотеки DLL на C++. Предположим, у меня есть эта структура классов:Дизайн интерфейса и наследование в C++

class IA 
{ 
public: 

    virtual void Foo() = 0; 
    ... 
}; 

class A : public IA 
{ 
public: 

    virtual void Foo() override { ... } 
    ... 
}; 

class IB 
{ 
public: 

    virtual void Bar() = 0; 
    ... 
}; 

class B : public IB 
    , public A 
{ 
public: 

    virtual void Bar() { ... } 
    ... 
}; 

Теперь, если у меня есть указатель на интерфейс IB, это не будет составлять:

IB* b = ...; 
b->Foo(); 

Чтобы заставить его работать, я должен был бы сделать IB не наследуют от IA, как таковой:

class IB : public IA 
{ 
    ... 
}; 

Но тогда это тоже не компилируется, потому что теперь B уже не конкретный класс, и компилятор ожидает, что он реализует IA::Foo, хотя он наследует от A.

Вы можете исправить это с помощью виртуального наследования:

class A : public virtual IA { ... }; 
class IB : public virtual IA { ... }; 
class B : public virtual IB, public A { ... }; 

который генерирует новое предупреждение в VC++:

warning C4250: 'B' : inherits 'A::A::Foo' via dominance 

Как я понимаю, это потому, что теперь есть больше чем одна декларация Foo.

Как правильно наследовать интерфейсы и их конкретную реализацию без этих проблем?

+0

@ DieterLücking Это было неправильно. Спасибо, что заметили это. Я починил это. :) – Zeenobit

+0

[Вот ответ, который объясняет C4250] (http://stackoverflow.com/questions/2190416/what-does-c4250-vc-warning-mean). Если вы в порядке с этим осложнением, тогда он должен работать нормально. – Guvante

+0

@Guvante Учитывая тот факт, что я использую виртуальное наследование для наследования интерфейсов, я не думаю, что столкнулся бы с таким осложнением. Значит, вы бы сказали, что можно просто отключить предупреждение? – Zeenobit

ответ

1

Подавить C4250 в настройках вашего компилятора и забыть об этом.

Мне неизвестны какие-либо проблемы с наследованием через господство. Другие компиляторы, которые я использую, никогда не предупреждают об этом даже на самых высоких уровнях предупреждения. Googling для c++ inheritance dominance problem вызывает только жалобы на C4250, никогда не описание какой-либо реальной проблемы с фактическим кодом. Я считаю, что это не проблема.

2

Как вы писали, это не компилируется:

IB* b = ...; 
b->Foo(); 

Конечно, это не компилируется, поскольку IB не имеет Foo члена. Чтобы получить доступ к Foo, вам понадобится указатель на IA, но IB* не может быть отлит до IA*.

Но есть точка, где вы получаете указатель на IB. В этот момент (или где-то вверх по линии) некоторый интерфейс должен знать об истинном объекте B, который также может быть отличен до IA, а не только до IB. В этот момент вы можете запросить IA* и использовать его как таковой.

Кто-то, имеющий IB*, может даже не знать, если реализация IB также является IA, или нет.


Другая возможность была бы определить литейный элемент на IB, что ставит под указатель на IA*. Как это:

IA * GetAsIA() = 0; 

IB реализации, которые IA, а может вернуть правильный указатель, другие реализации могут вернуться nullptr.

+0

Хотя я считаю, что это самый безопасный подход, я не думаю, что это решение будет хорошо масштабироваться для относительно большого проекта. Я думаю, что игнорирование предупреждения и обеспечение правильного шаблона интерфейса - лучшая альтернатива для моего дела. – Zeenobit

0

Пока IB не пытается реализовать IA где угодно, но A и вы понимаете, что B имеет реализацию IB, которая зависит от реализации AB «s реализация IA осуществляется A), вы можете безопасно игнорируйте это предупреждение.

Основная причина для предупреждения состоит в том, что вам обычно нужно искать вверх или вниз по иерархии наследования, чтобы найти все реализации, однако в этом случае вам нужно смотреть в боковом направлении от IB до A.

0

Если вы хотите удалить предупреждение, ответы на вопрос «Подавление C4250 в вашем компиляторе» являются опцией.

Однако, я думаю, что у вас плохой дизайн.

  • Ваш класс «B» зависит от конкретного класса (класс «A»).
  • Вы используете множественное наследование. Это очень немногие хорошие решения.

Я думаю, вы должны попытаться установить отношение Has-a вместо Is-a.

class IA 
{ 
public: 
    virtual void Foo() = 0; 
    ... 
}; 

class A : public IA 
{ 
public: 
    virtual void Foo() override { ... } 
    ... 
}; 

class IB 
{ 
public: 
    virtual void Bar() = 0; 
    ... 
}; 

class B : public IB 
{ 
private: 
    IA* ptrIA; 
public: 
    B(IA* ia): ptrIA(ia) {} 

    virtual void Bar() { ... } 
    void performeFoo() { ptrIA->Foo(); } 
    ... 
}; 
Смежные вопросы