Reputation: 1853
I am getting a compiler error when calling a method defined in a derived class. The compiler seems to think that the object I am referring to is of a base class type:
weapon = dynamic_cast<Weapon*>(WeaponBuilder(KNIFE)
.name("Thief's Dagger")
.description("Knife favored by Thieves")
.attack(7) // error: class Builder has no member called attack
.cost(10) // error: class Builder has no member called cost
.build());
Indeed, Builder
doesn't contain either attack
or cost
:
class Builder
{
protected:
string m_name;
string m_description;
public:
Builder();
virtual ~Builder();
virtual GameComponent* build() const = 0;
Builder& name(string);
Builder& description(string);
};
But the derived class WeaponBuilder
does:
enum WeaponType { NONE, KNIFE, SWORD, AXE, WAND };
class WeaponBuilder : public Builder
{
int m_cost;
int m_attack;
int m_magic;
WeaponType m_type;
public:
WeaponBuilder();
WeaponBuilder(WeaponType);
~WeaponBuilder();
GameComponent* build() const;
// should these be of reference type Builder or WeaponBuilder?
WeaponBuilder& cost(int);
WeaponBuilder& attack(int);
WeaponBuilder& magic(int);
};
I am not sure why the compiler cannot find the attack
or cost
method in the WeaponBuilder
class, as it is clearly present. I am also not sure why it recognizes the object as an instance of the base class Builder
.
Upvotes: 3
Views: 708
Reputation: 81349
It cannot find it because both name
and description
return a Builder&
instead of a WeaponBuilder&
, hence those other methods are not there. There is no clear solution for your code, other than casting everywhere.
You could rewrite the entire thing using CRTP and get ride of your problems, but its a significant change. Something among the lines of:
template< typename Derived >
class builder
{
Derived& name( std::string const& name ){ /*store name*/, return *derived(); }
Derived* derived(){ return static_cast< Derived* >( this ); }
};
class weapon_builder : builder< weapon_builder >
{
weapon_builder& attack( int ){ /*store attack*/ return *this; }
GameComponent* build() const{ return something; }
};
Note that with this approach all virtual
methods should go away, and you lose the ability to reference a plain builder
as it is no longer a common base type but a class template.
Upvotes: 6
Reputation: 11736
Your intention is probably something along these lines:
weapon = dynamic_cast<Weapon*>(dynamic_cast<WeaponBuilder &>(WeaponBuilder(KNIFE)
.name("Thief's Dagger")
.description("Knife favored by Thieves"))
.attack(7)
.cost(10)
.build());
Upvotes: 1