Reputation: 141
I'm in an intro to C++ class and I'm trying to find out why I'm getting a "no matching function for call" error. And I've looked through other posts, but those mainly seem to be problems with the constructors themselves.
This is simplified snippets:
In Base Class - Ship
// Members: shipName, shipBuiltYear
Ship::Ship(){ //implementation }
Ship::Ship(string name, string year){ //implementation }
void Ship::set(string name, string year){ //implementation }
In Derived Class - 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 }
In main
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
Is the problem that you can't use the base class to set the PirateShip, then use the PirateShip to set it again?
Do I have to change:
void PirateShip::set(int pirates){ //implementation }
to:
void PirateShip::set(string name, string year, string pirates)
{
Ship::set(name, year);
numPirates = pirates;
}
?
Or is there another way to do this?
Upvotes: 0
Views: 329
Reputation: 48665
If you know that an element is a specific type (and you must know that if you are calling with its specific parameter requirements) then you can cast to the appropriate type:
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
However I would question the design here. For polymorphism to work well, you should not need to know the exact types of the sub classes after creation.
Perhaps make the initialization call part of the constructor? Or configure the objects before adding them to the array?
ALSO
Using raw pointers to own objects is not considered good practice these days. I recommend a smart pointer:
std::unique_ptr<Ship> ships[2];
Also using built in arrays is similarly less than optimal in most cases. Consider a std::vector
:
std::vector<std::unique_ptr<Ship>> ships;
Or a std::array
if you want a fixed size:
std::array<std::unique_ptr<Ship>, 2> ships;
Upvotes: 0
Reputation: 275966
There are two problems here.
First:
Ship *ships[2] = {new Ship(), new PirateShip()};
this is an array of pointers to the Ship
part of two objects. The first is a Ship
, the second a PirateShip
. But you only have a pointer to the Ship
part of the PirateShip
, so can only (directly) interact with it.
If Ship
has virtual methods, then you could use RTTI and dynamic_cast
to query if a given Ship*
is pointing to the Ship
part of a PirateShip
like this:
auto* pirate = dynamic_cast<PirateShip*>(some_ship);
if pirate
is non-null, then some_ship
pointed at an Ship
piece of a PirateShip
.
Note that using dynamic cast is code smell; it probably means you should either improve the base class interface, or not have a pointer to base class here.
The second part is if you want to be able to call Ship::set
from PirateShip*
, you need to add
using Ship::set;
to the body of PirateShip
.
Upvotes: 1