从非模板基 class 指针调用模板派生 class 方法的方法
Invoke a method of templated derived class method from non-template base class pointer
我正在尝试在我的项目中实现一个类似于 Qt 中的 属性 系统的 属性 系统。我们刚刚开始提出一些想法,目前正处于 原型制作 阶段。
基本上,我从 Qt 中了解到,客户端应该能够通过 .h 文件中的一些宏传递 get 函数、set 函数和 属性 类型。所以我试着模仿一样。
以下是我的示例代码:
摘要getterclass。这种getterclass是属性Class
中的成员
class AbstractFunc
{
public:
template < typename R >
R Invoke ()
{
return (this)->Invoke ();
}
};
获取函数模板:Return 值可以是 T、T&、const T&、T* 等。
template < typename R, class T > class GetterFunction : public AbstractFunc
{
typedef R (T::*GetterFunc) ();
public:
GetterFunction (T * obj, GetterFunc func):m_Obj (obj), m_Func (func)
{
}
R Invoke ()
{
return m_Obj->*(m_Func) ();
}
public:
T * m_Obj;
GetterFunc m_Func;
};
属性 Class:
class Property
{
public:
Property (string name, AbstractFunc* getter):m_name (name), m_getter (getter)
{
}
template < typename R > R GetValue ()
{
return m_getter->Invoke < R > ();
}
private:
string m_name;
AbstractFunc* m_getter;
};
一些 Window Class:
class Window
{
public:
};
例子windowclass
class CheckBox :public Window
{
public:
int GetChecked ()
{
return m_checked;
}
void SetChecked (int nChecked)
{
m_checked = nChecked;
}
void AddProperty (string name)
{
m_prop = new Property (name, new GetterFunction< int, Checked >(this, &Checked::GetChecked));
}
int m_checked;
Property *m_prop;
};
主要功能:
int main ()
{
CheckBox cc;
cc.AddProperty ("Hello");
cout<<"value:"<< cc.m_prop->GetValue<int>();
return 0;
}
问题:
Getter 函数在 属性 Class 中被记为 AbstractFunc。我想在 AbstractFunc* 实例上调用 'Invoke',它应该调用成员函数和 return 正确的 return 类型 。上面的代码在 AbstractFunc::Invoke.
处抛出错误
您的 AbstractFunc
根本不是抽象的:它的 Invoke
不是虚拟的。因此,即使 GetterFunction
也有一个名为 Invoke
的方法,该方法实际上并没有覆盖 AbstractFunc::Invoke
;它只是隐藏它。当您尝试通过 AbstractFunc*
调用 Invoke
时,它会调用 AbstractFunc::Invoke
,这将进入无限递归并因此产生 UB。
我会按照@n.m.的建议来创建一个 class 层次结构,如下所示:
class AbstractFunc {
// lock down construction
AbstractFunc() = default;
public:
template<typename R>
R Invoke();
template<typename R>
bool HasType() const noexcept;
virtual ~AbstractFunc() = default; // need to have SOME virtual method so that we have runtime type info; also a virtual destructor is required anyway
template<typename R>
friend class TypedFunc;
};
template<typename R>
struct TypedFunc : AbstractFunc { // the ONLY instances of AbstractFunc are also instances of specializations of TypedFunc
virtual R InvokeTyped() = 0;
};
// one kind of TypedFunc applies a getter on an object
template<typename R, typename T>
struct GetterFunc : TypedFunc<R> {
// you never see a GetterFunc in the interface anyway... don't see a need to hide these
T *obj; // have you considered std::shared_ptr?
R (T::*getter)();
GetterFunc(T *obj, R (T::*getter)()) : obj(obj), getter(getter) { }
R InvokeTyped() override { return (obj->*getter)(); }
};
template<typename R, typename T>
std::unique_ptr<GetterFunc<R, T>> MakeGetterFunc(T *obj, R (T::*getter)()) {
return std::make_unique<GetterFunc<R, T>>(obj, getter);
}
// another kind applies a functor, etc.
template<typename R, typename F>
struct FunctorFunc : TypedFunc<R> {
F func;
template<typename... G>
FunctorFunc(G&&... args) : func(std::forward<G>(args)...) { }
R InvokeTyped() override { return func(); }
};
这已经可用了:如果您有一个 AbstractFunc*
或一个 AbstractFunc&
,您可以 dynamic_cast
将其缩小为预期类型的 TypedFunc
(例如 TypedFunc<int>
).如果成功(你得到一个非空指针或没有 std::bad_cast
异常),那么你只需调用 InvokeTyped
而不必知道是哪种 GetterFunc
/FunctorFunc
/whatever你实际上是在处理。在 AbstractFunc
中声明的函数 Invoke
和 HasType
只是帮助做到这一点的糖分。
template<typename R>
bool AbstractFunc::HasType() const noexcept {
return dynamic_cast<TypedFunc<R> const*>(this);
}
template<typename R>
R AbstractFunc::Invoke() {
return dynamic_cast<TypedFunc<R>&>(*this).InvokeTyped();
// throws std::bad_cast if cast fails
}
完成。
class Property {
std::string name;
std::unique_ptr<AbstractFunc> getter;
public:
Property(std::string name, std::unique_ptr<AbstractFunc> getter) : name(std::move(name)), getter(std::move(getter)) { }
template<typename R>
bool HasType() const noexcept { return getter->HasType<R>(); }
template<typename R>
R GetValue() const { return getter->Invoke<R>(); }
std::string const &GetName() const noexcept { return name; }
};
struct Window {
virtual ~Window() = default;
// doesn't really make sense to add/remove these from outside...
virtual std::vector<Property> GetProperties() = 0;
};
class CheckBox : public Window {
int checked = 0;
public:
int GetChecked() /*const*/ noexcept { return checked; }
void SetChecked(int checked) noexcept { this->checked = checked; }
std::vector<Property> GetProperties() override {
std::vector<Property> ret;
ret.emplace_back("Boxes Checked", MakeGetterFunc(this, &CheckBox::GetChecked));
return ret;
}
};
int main() {
CheckBox cb;
cb.SetChecked(5);
for(auto const &prop : cb.GetProperties()) std::cout << prop.GetName() << ": " << prop.GetValue<int>() << "\n";
}
然后您可以添加例如a virtual std::type_info const& GetType() const
或类似于 AbstractFunc
如果你希望能够直接获取类型等
我正在尝试在我的项目中实现一个类似于 Qt 中的 属性 系统的 属性 系统。我们刚刚开始提出一些想法,目前正处于 原型制作 阶段。 基本上,我从 Qt 中了解到,客户端应该能够通过 .h 文件中的一些宏传递 get 函数、set 函数和 属性 类型。所以我试着模仿一样。
以下是我的示例代码:
摘要getterclass。这种getterclass是属性Class
中的成员class AbstractFunc
{
public:
template < typename R >
R Invoke ()
{
return (this)->Invoke ();
}
};
获取函数模板:Return 值可以是 T、T&、const T&、T* 等。
template < typename R, class T > class GetterFunction : public AbstractFunc
{
typedef R (T::*GetterFunc) ();
public:
GetterFunction (T * obj, GetterFunc func):m_Obj (obj), m_Func (func)
{
}
R Invoke ()
{
return m_Obj->*(m_Func) ();
}
public:
T * m_Obj;
GetterFunc m_Func;
};
属性 Class:
class Property
{
public:
Property (string name, AbstractFunc* getter):m_name (name), m_getter (getter)
{
}
template < typename R > R GetValue ()
{
return m_getter->Invoke < R > ();
}
private:
string m_name;
AbstractFunc* m_getter;
};
一些 Window Class:
class Window
{
public:
};
例子windowclass
class CheckBox :public Window
{
public:
int GetChecked ()
{
return m_checked;
}
void SetChecked (int nChecked)
{
m_checked = nChecked;
}
void AddProperty (string name)
{
m_prop = new Property (name, new GetterFunction< int, Checked >(this, &Checked::GetChecked));
}
int m_checked;
Property *m_prop;
};
主要功能:
int main ()
{
CheckBox cc;
cc.AddProperty ("Hello");
cout<<"value:"<< cc.m_prop->GetValue<int>();
return 0;
}
问题: Getter 函数在 属性 Class 中被记为 AbstractFunc。我想在 AbstractFunc* 实例上调用 'Invoke',它应该调用成员函数和 return 正确的 return 类型 。上面的代码在 AbstractFunc::Invoke.
处抛出错误您的 AbstractFunc
根本不是抽象的:它的 Invoke
不是虚拟的。因此,即使 GetterFunction
也有一个名为 Invoke
的方法,该方法实际上并没有覆盖 AbstractFunc::Invoke
;它只是隐藏它。当您尝试通过 AbstractFunc*
调用 Invoke
时,它会调用 AbstractFunc::Invoke
,这将进入无限递归并因此产生 UB。
我会按照@n.m.的建议来创建一个 class 层次结构,如下所示:
class AbstractFunc {
// lock down construction
AbstractFunc() = default;
public:
template<typename R>
R Invoke();
template<typename R>
bool HasType() const noexcept;
virtual ~AbstractFunc() = default; // need to have SOME virtual method so that we have runtime type info; also a virtual destructor is required anyway
template<typename R>
friend class TypedFunc;
};
template<typename R>
struct TypedFunc : AbstractFunc { // the ONLY instances of AbstractFunc are also instances of specializations of TypedFunc
virtual R InvokeTyped() = 0;
};
// one kind of TypedFunc applies a getter on an object
template<typename R, typename T>
struct GetterFunc : TypedFunc<R> {
// you never see a GetterFunc in the interface anyway... don't see a need to hide these
T *obj; // have you considered std::shared_ptr?
R (T::*getter)();
GetterFunc(T *obj, R (T::*getter)()) : obj(obj), getter(getter) { }
R InvokeTyped() override { return (obj->*getter)(); }
};
template<typename R, typename T>
std::unique_ptr<GetterFunc<R, T>> MakeGetterFunc(T *obj, R (T::*getter)()) {
return std::make_unique<GetterFunc<R, T>>(obj, getter);
}
// another kind applies a functor, etc.
template<typename R, typename F>
struct FunctorFunc : TypedFunc<R> {
F func;
template<typename... G>
FunctorFunc(G&&... args) : func(std::forward<G>(args)...) { }
R InvokeTyped() override { return func(); }
};
这已经可用了:如果您有一个 AbstractFunc*
或一个 AbstractFunc&
,您可以 dynamic_cast
将其缩小为预期类型的 TypedFunc
(例如 TypedFunc<int>
).如果成功(你得到一个非空指针或没有 std::bad_cast
异常),那么你只需调用 InvokeTyped
而不必知道是哪种 GetterFunc
/FunctorFunc
/whatever你实际上是在处理。在 AbstractFunc
中声明的函数 Invoke
和 HasType
只是帮助做到这一点的糖分。
template<typename R>
bool AbstractFunc::HasType() const noexcept {
return dynamic_cast<TypedFunc<R> const*>(this);
}
template<typename R>
R AbstractFunc::Invoke() {
return dynamic_cast<TypedFunc<R>&>(*this).InvokeTyped();
// throws std::bad_cast if cast fails
}
完成。
class Property {
std::string name;
std::unique_ptr<AbstractFunc> getter;
public:
Property(std::string name, std::unique_ptr<AbstractFunc> getter) : name(std::move(name)), getter(std::move(getter)) { }
template<typename R>
bool HasType() const noexcept { return getter->HasType<R>(); }
template<typename R>
R GetValue() const { return getter->Invoke<R>(); }
std::string const &GetName() const noexcept { return name; }
};
struct Window {
virtual ~Window() = default;
// doesn't really make sense to add/remove these from outside...
virtual std::vector<Property> GetProperties() = 0;
};
class CheckBox : public Window {
int checked = 0;
public:
int GetChecked() /*const*/ noexcept { return checked; }
void SetChecked(int checked) noexcept { this->checked = checked; }
std::vector<Property> GetProperties() override {
std::vector<Property> ret;
ret.emplace_back("Boxes Checked", MakeGetterFunc(this, &CheckBox::GetChecked));
return ret;
}
};
int main() {
CheckBox cb;
cb.SetChecked(5);
for(auto const &prop : cb.GetProperties()) std::cout << prop.GetName() << ": " << prop.GetValue<int>() << "\n";
}
然后您可以添加例如a virtual std::type_info const& GetType() const
或类似于 AbstractFunc
如果你希望能够直接获取类型等