У меня есть класс под названием ValueChecker
которая имеет следующую функцию-член:
template<typename T>
bool ValueChecker::checkMe( std::ostringstream &oss, T &me) {
std::cout << "Default checkMe() for " << typeid(me).name() << std::endl;
return true;
}
Класс ValueChecker предназначен для выполнения простых проверок значений производного класса. checkMe () со временем станет специализированным для различных производных классов:
class Airplane : public ValueChecker {
friend class ValueChecker;
[...]
}template<>
bool ValueChecker::checkMe<Airplane>( std::ostringstream &oss, Airplane &me) {
...
/* Actually, this code is generated from a simple file which translates
* a simple language into C++ code. So that a non-developer can write
* the simple checks.
*
* ValueChecker itself has utility functions that may be called in the
* template specialization which are shared across all types.
*/
}
Это работает, но есть небольшая проблема с объявлением checkMe, когда вы смотрите на вызов:
int main() {
Airplane plane;
std::ostringstream oss;
if( plane.checkMe( oss, plane)) {
cout << "Values are bogus! " << oss.str() << endl;
return 0;
}
Я называю plane.checkMe (oss, plane). Но я мог бы также пропустить другой Самолет и не проверять самолет. Кроме того, вызов избыточен? То есть, теоретически, компилятор должен знать, какую функцию шаблона вызывать, основываясь на типе плоскости. Не должно быть необходимости передавать это как аргумент? В любом случае, было бы неплохо не исключать последний аргумент. Так что такой звонок был бы хорош:
if( plane.checkMe(oss)) { ... } // Calls the right template specialization.
Я просто не могу заставить его работать. Могут ли гуру C ++ помочь мне? Благодарю.
Возможно, вы захотите реализовать это как чисто виртуальный метод.
class ValueChecker
{
public:
virtual bool checkMe(std::ostringstream& oss) = 0;
};
class Airplane : public ValueChecker
{
public:
virtual bool checkMe(std::ostringstream& oss);
};
Таким образом, вы можете просто позвонить plane.checkMe(oss)
и будет вызван метод checkMe самолета.
Для данного кода вам не нужно использовать template
или же friend
, Вместо этого используйте наследование и сделайте checkMe()
метод как protected
а также virtual
метод. Затем переопределите checkMe()
метод в производном классе. Если вам не нужна реализация по умолчанию, вы также можете сделать ее чисто виртуальной. Вот небольшой фрагмент кода, основанный на вашем примере. (Обратите внимание на использование this
указатель.)
class ValueChecker {
protected:
virtual bool checkMe() {
std::cout << "Default checkMe() for " << typeid(this).name() << std::endl;
return true;
}
};
class Airplane : public ValueChecker {
public:
virtual bool checkMe() {
std::cout << "Airplane checkMe() for " << typeid(this).name() << std::endl;
return true;
}
};
int main() {
Airplane plane;
plane.checkMe();
}
Вам потребуется реализация по умолчанию, когда есть некоторая «общая» логика, которую вы хотите использовать в одном или нескольких производных классах, в дополнение к логике, специфичной для самого производного класса. В этом случае используйте оператор разрешения области видимости для доступа к логике базового класса.
bool Airplane::checkMe() {
std::cout << "Airplane checkMe() for " << typeid(this).name() << std::endl;
// use the "common" logic from the base class (if required)
ValueChecker::checkMe();
return true;
}
Есть часто встречающийся трюк: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
это может помочь вам.