假设我有3节课:
example.h
class Object {
public:
Object();
void pass_self_to_external_class();
};
class ObjectWithExtraMember : public Object {
public:
ObjectWithExtraMember();
int extra_member;
};
class ExternalClass {
public:
ExternalClass();
void do_something_with_object(Object* object);
void do_something_with_object(ObjectWithExtraMember* object);
int extra_member_val;
};
example.cpp
#include "example.h"
ExternalClass e;
Object::Object() {}
void Object::pass_self_to_external_class() {
e.do_something_with_object(this);
}
ObjectWithExtraMember::ObjectWithExtraMember() {
extra_member = 45;
}
ExternalClass::ExternalClass() {
extra_member_val = 0;
}
void ExternalClass::do_something_with_object(Object* object) {
extra_member_val = 0;
}
void ExternalClass::do_something_with_object(ObjectWithExtraMember* object) {
extra_member_val = object->extra_member;
}
如果
ObjectWithExtraMember
的实例调用pass_self_to_external_class
,有没有办法让pass_self_to_external_class
调用ExternalClass::do_something_with_object(ObjectWithExtraMember* object)
而不是ExternalClass::do_something_with_object(Object* object)
?我目前在实际项目中使用的解决方案是创建一个函数 ObjectWithExtraMember::pass_self_to_external_class
,其行为与 Object
版本完全相同,但是是否可以强制继承版本传递派生类的实例而不需要这样做?
我认为我们可以使用 CRTP 来处理这个问题。
class ExternalClass;
template<typename T>
class Object {
public:
Object() {}
void pass_self_to_external_class(ExternalClass &e);
T* get_instance() {
return static_cast<T*>(this);
}
};
class ObjectWithExtraMember : public Object<ObjectWithExtraMember> {
public:
ObjectWithExtraMember() {
extra_member = 45;
}
int extra_member;
};
class ExternalClass {
public:
ExternalClass() {
extra_member_val = 0;
}
template<class T>
void do_something_with_object(Object<T>* object) {
extra_member_val = object->get_instance()->extra_member;
}
// void do_something_with_object(ObjectWithExtraMember* object);
int extra_member_val;
};
template<typename T>
void Object<T>::pass_self_to_external_class(ExternalClass &e) {
if constexpr (std::is_void<T>::value == false) {
e.do_something_with_object(get_instance());
} else {
e.extra_member_val = 0;
}
}
测试代码。
int main(int, char**)
{
ExternalClass e;
Object<void> base;
base.pass_self_to_external_class(e);
cout << e.extra_member_val << endl;
ObjectWithExtraMember derived;
derived.pass_self_to_external_class(e);
cout << e.extra_member_val << endl;
ObjectWithExtraMember_plus derived1;
derived1.pass_self_to_external_class(e);
cout << e.extra_member_val << endl;
return 0;
}