C ++: использование базового класса в качестве реализации интерфейса - PullRequest
24 голосов
/ 10 сентября 2010

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

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

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

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

Спасибо.

Ответы [ 5 ]

12 голосов
/ 10 сентября 2010

Если 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;
}
8 голосов
/ 10 сентября 2010

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

class Interface
{
    virtual void myfunction() = 0;
}
class Base : public Interface
{
    virtual void myfunction() {/*...*/};
}
class Derived
    : public Base
{
    // myfunction is implemented by base
}
6 голосов
/ 10 сентября 2010

Нет. (все равно не так)

Вы можете быть введены в заблуждение из-за того, как все делается на других языках, таких как 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
}

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

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
}

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

1 голос
/ 10 сентября 2010

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

1 голос
/ 10 сентября 2010

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

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

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

Возможно, 'Derived::myfunction' может внутренне делегировать 'Base::myfunction'

.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...