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.

有帮助吗?

解决方案

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.

其他提示

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());
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top