Другим подходом может быть использование любопытно повторяющегося шаблона шаблона (CRTP) , наследуемого от интерфейса, который принимает сам тип в качестве параметра шаблона, помните, что вы можете уменьшить значение с помощью static_cast, и проблем нетс разрешением перегрузки, при использовании интерфейса в качестве параметра.Вы должны знать, что вы не можете использовать объект типа Person, если он не является подклассом.Таким образом, вы должны передавать объекты по ссылке на функции (что быстрее, чем копирование объекта) ... Вместо объекта типа Type, живущего внутри Person, Интерфейс живет внутри самого Типа.(Интерфейс не имеет никаких членов, когда наследуются пустые структуры, нет дополнительных затрат памяти, размер MySelf такой же, как и без наследования).При таком подходе никогда не используйте Person<Type>
без const&
, &
или &&
в списке параметров.
#include <iostream>
template <typename Type>
struct Person
{
/// this returns the subclass-object
Type &object() { return static_cast<Type&>(*this); }
Type const &object() const { return static_cast<Type const&>(*this); }
void walk(unsigned steps)
{
object().walk(steps);
}
void talk(const std::string &words) const /// const was eventually missing
{
object().talk(words);
}
protected:
~Person() = default; /// this disallows the user to construct an instance of this class that is not used as a base object
};
struct MySelf : Person<MySelf>
{
void walk(unsigned steps)
{
std::cout << "walking: " << steps << std::endl;
}
void talk(const std::string &words) const
{
std::cout << "talking: " << words << std::endl;
}
};
template <typename Type>
void testNConst(Person<Type>& object) /// works fine with instances of MySelf and Person<MySelf>
{
object.walk(50);
object.talk("testing");
}
template <typename Type>
void testConst(Person<Type> const& object)
{
object.talk("testing");
}
int main()
{
MySelf myself;
testNConst(myself); // compiles
testConst(myself); // compiles
return 0;
}
Некоторые другие советы
- всегда передают объекты по ссылкеесли вы хотите изменить объект
- всегда передавайте объекты по константной ссылке, если вы не хотите изменять объект
Edit
- защищенный деструкторпозволяет избежать создания экземпляра класса без производного класса, что не позволяет программисту иначе вызывать неопределенное поведение (
static_cast<Type&>
является критической точкой).