2010-09-10 2 views
21

В C++ можно использовать другой базовый класс для реализации реализации интерфейса (т. Е. Абстрактного базового класса) в производном классе?C++: использование базового класса в качестве реализации интерфейса

class Base 
{ 
    virtual void myfunction() {/*...*/}; 
} 
class Interface 
{ 
    virtual void myfunction() = 0; 
} 
class Derived 
    : public Base, public Interface 
{ 
    // myfunction is implemented by base 
} 

Вышесказанное должно составлять, но на самом деле не работает. Есть ли способ достичь этого эффекта?

В случае, если кто-либо заботится, причиной этого является то, что имеет смысл (для моего приложения) использовать общую библиотеку из другого пространства проектов/имен, чтобы обеспечить реализацию интерфейса в моем проекте. Я мог бы просто обернуть все, но это кажется большим количеством дополнительных накладных расходов.

Спасибо.

+3

может быть, если 'Base' унаследовал от' Interface' ... – djeidot

+0

+1 за ясный вопрос – Chubsdad

+1

@djeidot: '' Interface' и Derived' принадлежат к приложению 'Base' принадлежит библиотеке. Существует много случаев, когда нужно не иметь общие интерфейсы с библиотекой, - только повторно использовать реализацию для поддержки конкретных приложений. Функция ObjC (и количество других языков), но не работает на C++. – Dummy00001

ответ

10

Если Base не является производным от Interface, то вам необходимо будет переадресовывать звонки в Derived. Это только «накладные расходы» в том смысле, что вам приходится писать дополнительный код. Я подозреваю, что оптимизатор сделает его таким же эффективным, как если бы ваша оригинальная идея сработала.

class Interface { 
    public: 
     virtual void myfunction() = 0; 
}; 

class Base { 
    public: 
     virtual void myfunction() {/*...*/} 
}; 

class Derived : public Interface, public Base { 
    public: 
     void myfunction() { Base::myfunction(); } // forwarding call 
}; 

int main() { 
    Derived d; 
    d.myfunction(); 
    return 0; 
} 
+0

Это то, что я догадывался, что мне придется закончить. Должен ли я явно перенаправлять его или есть способ достичь того же с помощью директивы using? (например, используя Base :: myfunction();). Будет ли это работать? – deuberger

+0

Кто-нибудь знает наверняка, действительно ли оптимизатор сделает это столь же эффективным? Я использую gcc 4.5.1 в Fedora 13. – deuberger

8

Попробуйте это:

class Interface 
{ 
    virtual void myfunction() = 0; 
} 
class Base : public Interface 
{ 
    virtual void myfunction() {/*...*/}; 
} 
class Derived 
    : public Base 
{ 
    // myfunction is implemented by base 
} 
+4

Конечно, это предпочтительный способ. Тем не менее, OP говорит, что он хочет «использовать общую библиотеку из другого пространства проектов/имен, чтобы обеспечить реализацию интерфейса в моем проекте». Таким образом, я не думаю, что он может получить Base из интерфейса. – Sjoerd

+1

Я мог бы это сделать, так как я контролирую обе библиотеки, и я думал об этом, но это не имеет для меня никакого смысла со стороны дизайна. В другой библиотеке нет оснований для реализации этого интерфейса, и я думаю, что это запутает других пользователей библиотеки. – deuberger

1

Отклик в предположении, что производный класс хочет быть CONCRETE класс или не абстрактный класс, то есть желательно, чтобы иметь возможность создавать объекты типа 'Derived'.. Также я принимаю функции публичного участника в своем ответе.

№. Производный класс должен реализовать все чистые виртуальные функции, которые он наследует от всех базовых классов. В этом случае 'Base::myfunction' хотя унаследованной 'Derived' не рассматривается как реализация 'Derived::myfunction'

'Derived::myfunction' еще должен обеспечить реализацию 'Interface::myfunction'.

Одним из возможных вариантов может быть, что 'Derived::myfunction' может внутренне делегировать 'Base::myfunction'

Однако если не желательно, чтобы Derived был конкретным классом (который, я сомневаюсь, является целью OP), то вышеуказанное расположение классов прекрасное (с точки зрения языка)

1

Основание и интерфейс - совершенно разные типы. Как компилятор должен знать, что «myfunction» связан? Вы должны реализовать его в Derived, даже если эта реализация просто вызывает базовую версию.

6

No. (не тот путь так или иначе)

Вы могли бы ввести в заблуждение, кстати все сделано на других языках, как Java, C#, ActionScript и т.д.

В C++, множественное наследование и пути управляются виртуальные классы, что делает интерфейсы (используемые на других языках) устаревшими. На этих других языках интерфейсы используются для устранения проблем, возникающих из-за отсутствия множественного наследования (хорошего или плохого, это выбор).

Так что, если то, что вы хотите сделать, это просто обеспечить общий интерфейс с некоторыми виртуальными методами, обеспечивающих реализацию по умолчанию, просто реализовать в базовом классе:

class Interface 
{ 
    virtual void myfunction() { /*...*/ } ; //default implementation 
    virtual void yourFunction() = 0 ; // this one HAVE TO be implemented by the user 
} 
class Derived 
    : public public Interface // dont' need another clas 
{ 
    // myfunction is implemented by base 
    void yourFunction(); // have to implement yourFunction 
} 
class DerivedB 
    : public public Interface // dont' need another clas 
{ 
    void myFunction();// myfunction is implemented by base but we implement it for this specific class 
    void yourFunction(); // have to implement yourFunction 
} 

Однако, если вы хотите, чтобы обеспечить несколько базовых классов, имеют те же интерфейсы, то думаю, что ваш класс интерфейс основы других классов

// in this order 
class Interface 
{ 
    virtual void myfunction() = 0; 
} 
class BaseA : public Interface 
{ 
    // here "virtual" is optional as if the parent is virtual, the child is virtual too 
    virtual void myfunction() {/*...*/}; // BaseA specific implementation 
} 
class BaseB : public Interface 
{ 
    virtual void myfunction() {/*...*/}; // BaseB specific implementation 
} 

Существует, однако, не-очень-легко читаемый (читай: не Рекоммендуемый) способ обеспечить реализацию по умолчанию НО принуждение пользователя к e xplicitely сказать, если он хочет использовать это или нет. Это использует тот факт, что даже чисто виртуальные функции могут иметь реализацию по умолчанию, которые могут быть названы:

class Interface 
{ 
    virtual void myfunction() { /*...*/ } ; //default implementation 
    virtual void yourFunction() = 0 ; // this one HAVE TO be implemented by the user BUT provide a default implementation! 
} 

// in Interface.cpp 

void Interface::yourFunction() // default implementation of the virtual pure function 
{ /*...*/ } 

// in Derived.h 

class DerivedA 
    : public public Interface // dont' need another clas 
{ 
    // myfunction is implemented by base 
    void yourFunction(); // have to implement yourFunction -- DerivedA specific 
} 

class DerivedB 
    : public public Interface // dont' need another clas 
{ 
    void myFunction();// myfunction is implemented by base but we implement it for this specific class 
    void yourFunction() { Interface::yourFunction(); } // uses default implementation of yourFunction, hidden but existing 
} 

Но не делайте этого.

+0

+1, отметив, что C++ и Java/C# отличаются в этом вопросе. – Sjoerd

+0

Вы правы, у меня изначально была идея, основанная на моем опыте в Java и C#, но потом поняла, что то же самое не будет работать на C++. Я не уверен, думаю, что это хорошо или плохо, но, конечно, было бы легче, если бы это сработало, но я знаю, что есть веская причина, по которой это не так. – deuberger

+0

У вас больше выбора, чем на предыдущих языках, но это также дает вам больше последствий. Я был бы вами, единственный вопрос: будет ли я предлагать несколько реализаций по умолчанию? Если нет, переходите к первому простому решению (просто определите реализацию по умолчанию в нечистых виртуальных функциях); в противном случае вам понадобится «иерархия понятий», представленная иерархией классов в качестве второго примера. – Klaim

Смежные вопросы