C ++ Реализация подклассов, расширяющих подинтерфейсы без переопределения уже переопределенных методов

0

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

Вот ошибки:

main.cpp: In function 'int main()':
main.cpp:36:38: error: cannot allocate an object of abstract type 'Subclass'
     Subclass * subObj = new Subclass();
                                      ^
Subclass.h:13:7: note:   because the following virtual functions are pure within 'Subclass':
 class Subclass : SubInterface {
       ^
SuperInterface.h:13:18: note:   virtual void SuperInterface::doSomething()
     virtual void doSomething()=0;

Вот мои источники:

#include <iostream>

class SuperInterface {
public:
    virtual void doSomething() = 0;
protected:
    int someValue;
};

class SubInterface : public SuperInterface {
public:
    virtual void doSomethingElseThatHasNothingToDoWithTheOtherMethod() = 0;
protected:
    int anotherValue;
};

class Superclass : public SuperInterface {
public:
    Superclass() {}
    virtual ~Superclass() {}
    void doSomething() {std::cout << "hello stackoverflow!";}
};

class Subclass : public SubInterface {
public:
    Subclass() {}
    virtual ~Subclass() {}
    void doSomethingElseThatHasNothingToDoWithTheOtherMethod() {std::cout << "goodbye stackoverflow!";}

};

int main(void)
{
    Superclass * superObj = new Superclass();
    Subclass * subObj = new Subclass();
}

Вот то, что я хочу: я хочу, чтобы моя реализация была в курсе и поэтому имела такое же поведение, как и уже переопределенные методы (например, subObj->doSomething() работает без необходимости его повторного использования). Может ли кто-нибудь сказать мне, что я должен сделать, чтобы это произошло, если это возможно? Благодарю.

  • 0
    Просто разбираю твой код моими глазами. Похоже, что Subclass объявляет doSomethingElse как чисто виртуальный. Это опечатка, правильно?
  • 1
    Публично получить, избавиться от = 0 в объявлении Subclass :: doSomethingElse и реализовать doSomething в Подклассе. Что ж, вам не нужно извлекать данные публично, но это, вероятно, то, что вы хотите. Классы наследуют конфиденциально по умолчанию. Я использую структуры для чистых интерфейсов.
Показать ещё 5 комментариев
Теги:
inheritance
abstract-class

5 ответов

2
Лучший ответ

Нет, вы не можете делать то, что хотите, через простое наследование. Ни в doSomething() не наследует или не обеспечивает реализацию doSomething(), поэтому вы не можете вызвать subObj->doSomething() по вашему желанию. Вы должны соблюдать контракт интерфейса subInterface.

Вы можете наследовать Subclass из Superclass и Subinterface и просто реализовать doSomething() как своего рода прокси-сервер, Superclass::doSomething(). Вы все еще нуждаетесь в реализации, но вам не нужно "повторно реализовывать" ее.

2

Вы получаете ошибку, потому что пытаетесь создать объект абстрактного класса. Ваш Subclass является абстрактным классом из-за этой строки void doSomethingElse()=0; , Если класс имеет одну чистую виртуальную функцию, это будет абстрактный класс. Вы не можете создать объект абстрактного класса, у вас может быть только ссылка или указатель на него.

Чтобы избавиться от ошибки, объявление doSomethingElse в Subclass должно быть

void doSomethingElse();

Вместо void doSomethingElse()=0;

Также я не понимаю, почему вам нужны два интерфейса. Вы можете получить Subclass из SuperInterface, поскольку он в основном такой же, как SubInterface

  • 0
    doSomethingElse () переименован, чтобы прояснить, что doSomething () и doSomethingElse () не имеют абсолютно ничего в общем. Я также могу иметь совершенно другое поведение и тип возвращаемого значения. = 0 была опечатка теперь исправлена!
0

Ваш класс "Подкласс" должен переопределить 2 чистых виртуальных метода, поэтому:

class Subclass : SubInterface {
public:
    Subclass();
    virtual ~Subclass();
    void doSomethingElse() override;
    void doSomething() override;
};

не делая этого или заявляя

void doSomethingElse() = 0;

класс Подкласс также становится абстрактным, который не может быть создан. Вы могли бы взглянуть на: http://www.parashift.com/c++-faq-lite/pure-virtual-fns.html

Вот то, что я хочу: я хочу, чтобы моя реализация была в курсе и поэтому имела такое же поведение, что и для уже переопределенных методов (например, subObj-> метод doSomething() работает без необходимости его повторного использования). Может ли кто-нибудь сказать мне, что я должен сделать, чтобы это произошло, если это возможно??? Благодарю.

→ возможно объявить методы виртуальными не чистыми виртуальными

  • 1
    Может добавить «переопределить» к объявлениям метода.
  • 0
    да, действительно, изменение (+1 за замечание)
Показать ещё 1 комментарий
0

Честно говоря, я не совсем уверен, что ваш дизайн хочет выразить, но здесь есть как минимум две технические ошибки:

1.) Во всех случаях вы используете личное наследование, так что на самом деле вы вообще не имеете дело с "интерфейсами". Доступ к государственному наследованию осуществляется следующим образом:

class SubInterface : public SuperInterface

2.) Вы используете =0 для функции, которую вы, по-видимому, хотите реализовать.

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

class CommonFunctionality
{
//...
public:
    void doSomething();
    void doSomethingElse();
};

class SuperClass
{
//...
private:
    CommonFunctionality m_functionality;
};

class SubClass : public SuperClass
{
//...
private:
    CommonFunctionality m_functionality;
};

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

  • 0
    Это опечатка, мой плохой, и я переименовал другой метод, чтобы было ясно, что оба метода ведут себя по-разному. Кстати, добавление «public» в оператор наследования ничего не меняет в ошибках
0

Есть 2 проблемы, которые четко сформулированы компилятором:

Проблема 1

SubInterface::doSomethingElse()() в Subclass объявляется чистым виртуальным, не SubInterface::doSomethingElse()(), что вы пытаетесь определить его в исходном файле (я уверен, что это ошибка копирования).


class Subclass : SubInterface
{
public:
    Subclass();
    virtual ~Subclass();
    void doSomethingElse() = 0; // still pure? 
};

Решение очевидно:


class Subclass : SubInterface
{
public:
    Subclass();
    virtual ~Subclass();
    virtual void doSomethingElse() override 
    {   
    }

};

(здесь используется спецификатор override C++ 11, поэтому компилятор проверяет правильность переопределения, не обязательно)

Проблема 2

doSomething() даже не пытается переопределяться ни в SuperInterface, ни в Subclass, поэтому он остается чистым виртуальным. Хотя doSomething() переопределяется в Superclass, Subclass не имеет понятия о существовании Superclass.

Изображение 174551

Решение: переопределить doSomething() либо в SuperInterface, либо в Subclass, либо в любом из дочерних Subclass (их еще нет). Например, переопределение в Subclass:


class Subclass : SubInterface
{
public:
    Subclass();
    virtual ~Subclass();
    virtual void doSomething() override 
    {   
    }

    virtual void doSomethingElse() override 
    {   
    }

};

Другие вопросы:

  • Вы наследованию без видимости спецификатора, то есть privat Ely. Используйте public наследование, пока вам не понадобится что-то еще:

    class Derved : public Base {};
    
  • В ваших исходных файлах есть расширение .c, но содержит код C++. Это может смутить некоторых компиляторов, если вы явно не укажете язык программирования с помощью аргументов командной строки. По соглашению большинство программистов используют расширение .cpp, и большинство компиляторов обрабатывают такие файлы, как C++ исходные файлы.

  • 0
    исправление моего кода. Правда в том, что я случайно удалил часть своего кода. Я также сделал некоторые изменения, чтобы сделать все это, я надеюсь, яснее!
  • 0
    @PaikuHan Хорошо, так что первая проблема решена, другие все еще там.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню