سؤال

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