В продолжение моего предыдущего вопроса: Как вернуть производный тип?
I have a Validator class and derived classes from it; When i'm trying to return pointer to derived class then method return base class(Validator) instead of 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???
The same virtual method name() working as i want, but validateAttribute() called from base class only.





Посмотрите внимательно, как вы определили void RequiredValidator::validateAttribute()
Вы можете заметить, что подпись немного отличается от базовой (std::string &attribute не const)
есть ключевое слово override, которое поможет компилятору улавливать такие типы опечаток.
подпись validateAttribute должна быть идентична в базе и в производном классе
Только одно: неопределенная ссылка на `Validator :: name [abi: cxx11] () const '. Как это исправить?
@exru: там написано, что не хватает реализации virtual std::string name() const;.
Спасибо, братан, я исправил сам. Там написано, что: 1. слушать компилятор 2. учить английский 3. читать документы и т. д. Все проблемы на моем плохом английском. Но я стараюсь)) И я много времени проводил с PHP. Пишу на C++ всего 2 месяца))) Спасибо за помощь.
§13.1 where the Standard discusses about declarations that cannot be overloaded states -
Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored [...]
Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations. [...]
when determining which function is being declared, defined, or called. "In particular, for any type T, “pointer to T,” “pointer to const T,” and “pointer to volatile T” are considered distinct parameter types, as are “reference to T,” “reference to const T,” and “reference to volatile T.”
Следовательно,
void validateAttribute(Model &model, std::string &attribute) override;
это не то же самое, что
void validateAttribute(Model &model, const std::string &attribute);
C++11 или новее с использованием ключевого слова 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;
@exru, на самом деле, если бы была константа, но не ссылка, тогда было бы нормально перегрузить, т.е. void validateAttribute(Model &model, std::string attribute) и void validateAttribute(Model &model, const std::string &attribute) не имели бы этой проблемы. (НО, конечно, это не то, что мы хотим делать ...) Я просто хотел уточнить точку. Разница только для использованная литература и указатели! Для них const имеет значение.
Спасибо, бро. Я исправил!
@JoeyMallone Вы имели в виду const std::string attribute во второй подписи вашего комментария? Потому что T и const T имеют одинаковые искажения в подписях, но T и const T& определенно не ...
@MaxLanghof, да. Но сейчас я не могу редактировать комментарий. :( Я имею в виду, нет, void validateAttribute(Model &model, std::string attribute) и void validateAttribute(Model &model, const std::string attribute) можно было бы перегрузить. В обоих объявлениях нет &.
Удалив весь ненужный код, давайте посмотрим на сигнатуры базового и унаследованного классов:
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& attribute.
Конфликт здесь - const std::string& и std::string&. Либо сделайте две функции точно совпадающими заранее, либо, в вашем случае, поскольку вы пытаетесь использовать полиморфизм, вы можете исправить это в своем производном классе, выполнив следующие действия:
/*virtual*/ void validateAttribute( Model& model, std::string& string ) override;
Ключевое слово override здесь вызовет ошибку компилятора, объясняющую, в чем заключается ваша проблема. Не забудьте также добавить virtual, если вы планируете наследовать от этого производного класса.
Нужно ли мне переопределить тогда "виртуальное" ключевое слово? Потому что «ошибка: невиртуальная функция-член, помеченная как« переопределить », скрывает виртуальную функцию-член»