如何调用精确派生类方法?

时间:2019-01-15 10:11:47

标签: c++ polymorphism

在继续我之前的问题: How to return derived type?

  

我有一个Validator类和从中派生的类;当我尝试   返回指向派生类的指针,然后方法返回基数   class(Validator)而不是Derived。

我将我的课程修改为下一个:

class Validator
{
public:
    std::string m_name = "BaseValidator";

    static const std::map<std::string, Validator *> validators();

    void validateModel(Model &model, const std::vector<std::string> &attrNames);
    static Validator *getByName(std::string &name);

    virtual void validateAttribute(Model &model, const std::string &attribute);
    virtual ~Validator();

    virtual std::string name() const;
};

const std::map<std::string, Validator*> Validator::validators()
{
    std::map<std::string, Validator*> result;
    result["required"] = new RequiredValidator();
    return result;
}

void Validator::validateModel(Model &model, const std::vector<std::string> &attrNames)
{      
     validateAttribute(model, name.at(0));    
}

Validator* Validator::getByName(std::string &name)
{
    auto g_validators = Validator::validators();
    auto validator = g_validators.find(name);
    if(validator != g_validators.end()){
        return validator->second;
    }else{
        std::cerr << "Unknow type of validator: " << name << std::endl;
    }
    return nullptr;
}

void Validator::validateAttribute(Model &model, const std::string &attribute)
{
    (void)model;
    (void)attribute;
    std::cout << this->name() << std::endl;
}

//------------------

class RequiredValidator : public Validator
{
public:
    std::string m_name = "RequiredValidator";

    void validateAttribute(Model &model, std::string &attribute);
    ~RequiredValidator();
    std::string name() const;
};


std::string RequiredValidator::name() const
{
    return m_name;
}

void RequiredValidator::validateAttribute(Model &model, std::string &attribute)
{
    (void) model;
    (void) attribute;
    std::cout << "RequiredValidator!!!" << std::endl;
}

RequiredValidator::~RequiredValidator()
{

}


//------------------

auto validator = Validator::getByName("required");

validator->name();// will output RequiredValidator

//next i'm calling 

validator->validateModel(); // whos calling validateAttribute() inside
//and it's output Validator::validateAttribute() //but i wan't
//RequiredValidator::validateAttribute(); 
//where i was wrong with logic???
  

相同的虚拟方法name()如我所愿,但是   仅从基类调用validateAttribute()。

3 个答案:

答案 0 :(得分:3)

仔细查看您如何定义void RequiredValidator::validateAttribute()

您可能会注意到签名与基本签名略有不同(std::string &attribute不是const

有一个关键字override,可以帮助编译器捕获这些类型的错字。

答案 1 :(得分:2)

  • 首先,正如其他人所指出的,
  

§13.1,其中标准讨论了不能为   重载状态-

     

仅在是否存在   const和/或volatile是等效的。也就是说,const和volatile   每个参数类型的类型说明符都会被忽略[...]

     

仅在最外层的const和volatile类型说明符   以这种方式忽略参数类型规范; const   以及隐藏在参数类型中的易失类型说明符   规格很重要,可以用来区分   重载的函数声明。 [...]

     

在确定要声明,定义或调用的函数时。   “尤其是对于任何类型T,“指向T的指针”,“指向const T的指针”   和“易失性T的指针”被认为是不同的参数类型,   就像“引用T”,“引用const T”和“引用   易挥发的T。”

因此

void validateAttribute(Model &model, std::string &attribute) override;

不同
void validateAttribute(Model &model, const std::string &attribute);
  • 第二,如果您在函数声明中使用C++11关键字使用override或更高版本,则可以避免遇到此类错误,如下所示。

使用 override 关键字,除非派生类中的函数签名与基类中的函数签名匹配,否则此代码将不允许您编译!

class RequiredValidator : public Validator
{
public:
    std::string m_name = "RequiredValidator";

    void validateAttribute(Model &model, std::string &attribute) override;
    ~RequiredValidator();
    std::string name() const;
};

编辑:p.s. override需要virtual关键字。因此,

virtual void validateAttribute(Model &model, std::string &attribute) override;

答案 2 :(得分:2)

删除所有不相关的代码,让我们看一下基类和继承类的签名:

var getRowMetadata = function(old_metadata_provider) {
    return function (row) {
        var item = this.getItem(row),
            ret = old_metadata_provider(row);

        //Handle group rows
        if (item.__group) {
            //adding a class
            ret.cssClasses += ' ' + (item.collapsed === 1 ? 'collapsed' : 'expanded');
            //or trigger a custom event....
        }
        //"Normal rows"
        else if (item) {
            ret = ret || {};
            ...
        }
        return ret;
    };
};


....

dataview = new Slick.Data.DataView({
    groupItemMetadataProvider: groupItemMetadataProvider,
    inlineFilters: true
});
dataview.getItemMetadata = getRowMetadata(dataview.getItemMetadata);

在基类的class Validator { public: virtual void validateAttribute(Model &model, const std::string &attribute); }; class RequiredValidator : public Validator { public: void validateAttribute(Model &model, std::string &attribute); }; 中,其参数为::validateAttribute()Model& model,在派生类的const std::string& attribute中,其参数为::validateAttribute(),和Model &model

这里的冲突是std::string& attributeconst std::string&。要么事先使这两个函数完全匹配,要么在您的情况下使它们完全匹配,因为您正尝试使用多态性,因此可以在派生类中通过以​​下操作解决此问题:

std::string&

此处的/*virtual*/ void validateAttribute( Model& model, std::string& string ) override; 关键字将为您生成一个编译器错误,以解释您的问题所在。如果您打算从此派生类继承,也不要忘记添加override