【问题标题】:Can't call method of derived class - compiler identifies object instance as base class无法调用派生类的方法 - 编译器将对象实例识别为基类
【发布时间】:2012-12-11 00:13:24
【问题描述】:

调用派生类中定义的方法时出现编译器错误。编译器似乎认为我所指的对象是基类类型:

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());

确实,Builder 不包含attackcost

class Builder
{
protected:

    string m_name;
    string m_description;

public:

    Builder();
    virtual ~Builder();
    virtual GameComponent* build() const = 0;

    Builder& name(string);
    Builder& description(string);
};

但是派生类WeaponBuilder 可以:

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);

};

我不确定为什么编译器在 WeaponBuilder 类中找不到 attackcost 方法,因为它显然存在。我也不确定为什么它将对象识别为基类Builder 的实例。

【问题讨论】:

    标签: c++ inheritance methods compiler-errors base-class


    【解决方案1】:

    它找不到它,因为namedescription 返回一个Builder&amp; 而不是WeaponBuilder&amp;,因此这些其他方法不存在。除了到处强制转换之外,您的代码没有明确的解决方案。

    您可以使用 CRTP 重写整个事情并解决您的问题,但这是一个重大的变化。诸如此类的东西:

    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; }
    };
    

    请注意,使用这种方法,所有 virtual 方法都应该消失,并且您无法引用普通的 builder,因为它不再是常见的基类型而是类模板。

    【讨论】:

    • 我看到了问题,因为在对namedescription 的方法调用之后,我返回了对Builder 的引用。德拉斯。
    • 这种模式是否适用于多个继承Builder 类的对象?我的想法是为游戏中的每个复杂对象使用Builder
    • @Dylan:是的,它有效,您可以使用此模式创建不同的 builders,它们都共享相同的 implicit 接口。但是请注意,除了 implicit 接口之外,这些类型之间没有任何共同点,否则它们是完全不相关的类型。
    • 我实现了上述操作,但是当我在 main 中创建 WeaponBuilder 对象时调用模板类中定义的 namedescription 的成员时,我收到“未找到符号”错误。
    • @Dylan: 哦,是的,是的,template 方法必须在头文件中定义。
    【解决方案2】:

    你的意图可能是这样的:

    weapon = dynamic_cast<Weapon*>(dynamic_cast<WeaponBuilder &>(WeaponBuilder(KNIFE)
    .name("Thief's Dagger")
    .description("Knife favored by Thieves"))
    .attack(7)    
    .cost(10)     
    .build());
    

    【讨论】:

    • 这消除了调用attack 方法时的错误,但对我来说仍然导致cost 处的编译器错误。
    猜你喜欢
    • 2016-07-06
    • 2013-03-28
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    • 2021-09-10
    • 2023-02-03
    相关资源
    最近更新 更多