Передать абстрактный параметр в метод, почему бы и нет?

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


person Jack    schedule 06.12.2013    source источник
comment
Это половина смысла использования наследования. Просто пусть метод принимает указатель на абстрактный класс, а затем вы можете передать ему указатель на любой производный класс.   -  person Taylor Brandstetter    schedule 07.12.2013
comment
Учитывая, что класс абстрактный, я понимаю, что не могу передать абстрактный класс ни одному методу. Это верно только, если вы ограничиваете себя передачей по значению. Как правило, при работе с абстрактным и вообще с любым базовым / материнским классом используется полиморфизм (передача по ссылке или передача по адресу указателя).   -  person Stephane Rolland    schedule 07.12.2013


Ответы (3)


Вам необходимо указать параметр как указатель (или ссылку), например. Abstract *, а не Abstract. Если Derived наследуется от Abstract, вы можете передать переменную типа Derived *, когда ожидается Abstract *, но, как правило, вы не можете передать переменную типа Derived, когда ожидается Abstract.

person GS - Apologise to Monica    schedule 06.12.2013
comment
В чем причина этого? Какой смысл ограничивать использование параметров? - person Jack; 07.12.2013
comment
@Jack Потому что вы не можете создать экземпляр абстрактного класса. - person smac89; 07.12.2013
comment
@ Smac89 - даже если бы вы могли, передача по значению разрезала бы объект. - person Pete Becker; 07.12.2013
comment
Вы можете пройти по указателю или по ссылке. И обратите внимание, что приведение - это что-то, что вы пишете в исходном коде, чтобы указать компилятору выполнить преобразование. Существует неявное преобразование из Derived* в Abstract* и неявное преобразование из Derived& в Abstract&. Ни для того, ни другого не требуется. - person Pete Becker; 07.12.2013
comment
@Jack Если вы попытаетесь заставить вашу функцию принимать Abstract по значению, она создаст копию переданного объекта. Вы не можете создать копию Abstract, потому что она абстрактная. И даже если бы он не был абстрактным, копировалась бы только часть объекта базового класса. Передача по ссылке - это нормально, по сути, это то же самое, что передача по указателю, только с другим синтаксисом. - person Taylor Brandstetter; 07.12.2013
comment
@PeteBecker: Что вы имеете в виду под срезом? - person Jack; 07.12.2013
comment
@Jack - нарезка происходит, когда вы передаете объект производного типа функции, которая принимает объект базового типа по значению. Производный объект преобразуется в базовый объект, поэтому все, что вы получаете, - это базовая часть: производная часть обрезается. - person Pete Becker; 07.12.2013
comment
Спасибо за замечания по терминологии и ссылки - я улучшил ответ. Я почти упомянул ссылки для начала, но затем у меня возник момент сомнения в том, будут ли они охвачены, поэтому не упомянул об этом. - person GS - Apologise to Monica; 07.12.2013

Затем вы используете полиморфизм в C ++.

Учитывая любой базовый класс:

struct Base{};

и его подклассы:

struct SubClassA : public Base(){};
struct SubClassB : public Base(){};

Если вы заявляете:

void MyFunctionReference(Base&){};
void MyFunctionPointer(Base*){};

Затем вы можете позвонить:

{
   SubClassA a;
   SubClassB b;

   MyFunctionReference(a); // by reference
   MyFunctionPointer(&b); // by pointer address
}
person Stephane Rolland    schedule 06.12.2013

Вы действительно можете это сделать, обратите внимание:

Чистый абстрактный класс:

class Abstract {
public:
    virtual void foo() = 0;
};

Дочерний элемент переопределения функции-члена:

class AbstractImpl : public Abstract {
public:
    void foo() override { std::cout << "Hi from subclass\n"; }
};

Теперь мы объявляем метод, который принимает ссылочный тип абстрактного класса

void somefunc(Abstract &ab) {
    ab.foo();
}

Наконец, в основном мы создаем экземпляр параметра дочернего класса

int main() {
    AbstractImpl test;
    somefunc(test); // prints Hi from subclass
    return 0;
}

Источник: https://stackoverflow.com/a/11422101/2089675

person smac89    schedule 06.12.2013