В полиморфизме C ++, как избежать сокрытия имени для функций (нет подходящей функции для ошибки вызова)? - PullRequest
0 голосов
/ 03 декабря 2018

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

Это упрощенные фрагменты:

В Базовом классе - Корабль

// Members: shipName, shipBuiltYear
Ship::Ship(){ //implementation }
Ship::Ship(string name, string year){ //implementation }
void Ship::set(string name, string year){ //implementation }

В производном классе - PirateShip

// Members: numPirates
PirateShip::PirateShip() : Ship() { //implementation }
PirateShip::PirateShip(string name, string year, string pirates) : ship(name, year){ //implementation }
void PirateShip::set(int pirates){ //implementation }

В основном

Ship *ships[2] = {new Ship(), new PirateShip()};
ships[0] -> set("Luvinia", "2020"); // using setter from base class
ships[1] -> set("Skylin", "2030"); // using setter from base class
ships[1] -> set(100); // using setter from derived class

Проблема в том, что вы не можете использовать базовый класс для установки PirateShip, затем используйте PirateShip для установкиэто снова?

Должен ли я изменить:

void PirateShip::set(int pirates){ //implementation }

на:

void PirateShip::set(string name, string year, string pirates)
{ 
    Ship::set(name, year);
    numPirates = pirates; 
}

?

Или есть другой способ сделать это

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

Если вы знаете , что элемент относится к определенному типу (а вы должны знать, что если вы вызываете его с конкретными требованиями к параметрам), то вы можете приведите к соответствующему типу:

Ship* ships[2] = {new Ship(), new PirateShip()};
ships[0] -> set("Luvinia", "2020"); // using setter from base class
ships[1] -> set("Skylin", "2030"); // using setter from base class
dynamic_cast<PirateShip*>(ships[1]) -> set(100); // change to the correct interface

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

Возможно, сделать вызов инициализации частью конструктора?Или настроить объекты до , добавив их в массив?

ТАКЖЕ

Использование необработанных указателей на собственных объектов не являетсясчитается хорошей практикой в ​​эти дни.Я рекомендую умный указатель :

std::unique_ptr<Ship> ships[2];

Кроме того, использование встроенных массивов в большинстве случаев аналогично менее оптимально.Рассмотрим std::vector:

std::vector<std::unique_ptr<Ship>> ships;

или std::array, если вы хотите фиксированный размер:

std::array<std::unique_ptr<Ship>, 2> ships;
0 голосов
/ 03 декабря 2018

Здесь есть две проблемы.

Первое:

Ship *ships[2] = {new Ship(), new PirateShip()};

Это массив указателей на Ship часть двух объектов.Первый - Ship, второй - PirateShip.Но у вас есть только указатель на Ship часть PirateShip, поэтому вы можете только (напрямую) взаимодействовать с ним.

Если Ship имеет виртуальные методы, вы можете использовать RTTI и dynamic_cast для запроса, если данный Ship* указывает на Ship часть PirateShip следующим образом:

auto* pirate = dynamic_cast<PirateShip*>(some_ship);

, если pirate не нуль, то some_ship указывает наShip кусок PirateShip.

Обратите внимание, что использование динамического приведения - это запах кода;это, вероятно, означает, что вам следует либо улучшить интерфейс базового класса, либо не указывать здесь указатель на базовый класс.


Вторая часть - если вы хотите иметь возможность вызывать Ship::set из PirateShip*, вам нужно добавить

using Ship::set;

к телу PirateShip.

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