gpt4 book ai didi

c++ - 自动向下转换指向派生对象的指针

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:03:20 25 4
gpt4 key购买 nike

早上好

我有一个模板化类,我想通过指针 vector 来操作对象。要使用指向模板化类的指针 vector ,我需要从非模板化类派生此类,我做到了。

这是我的问题:要从指向基类的指针调用派生类的方法,我不能使用虚函数,因为不能将模板函数设为虚函数。我需要进行显式转换,这很乏味:一旦使用 new 创建数字对象,实际上需要向下转换为 number*,尽管该对象事先已知为数字。

我以一种笨拙的方式解决了这个问题:函数 myset 测试所有支持的 typeid 值以获得正确的动态转换。它是执行 typeid 检查的一长串嵌套 ifs。

除了繁琐之外,该函数仅适用于调用'set'方法,并且应定义类似的函数以调用其他方法。如果我可以对我指向的对象类型进行自动转换,一切都会简单得多。

该方法的缺点是:

  1. 代码是重复的:如果我定义了另一个函数(例如 T get() {return val;},我将需要另一个带有全套嵌套 ifs 的 myget 函数!
  2. 支持的类型列表必须通过嵌套 if 调用显式定义
  3. 代码可能效率低下

编译器知道 lst[0](在下面的代码中)指向一个数字对象,尽管 lst 是一个元素对象的 vector ,从中派生出 number<> 个对象。

是否有一种方法可以自动将定义为 base* 的指针向下转换为指向实际指向的对象的指针?

如果我有正确的向下转换,那么我可以在 number<> 类中定义数千个方法并使用正确转换 -> function(...) 调用调用它们

代码如下(可以正常运行,核心是“myset”的定义)

提前致谢,彼得罗 M.

PS 我最感兴趣的是标准 C++ 方法,而不使用除 STL 之外的其他库,例如 Boost。

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

class element
{
public:
virtual void print() = 0; // print is not templatized and works properly
//template <class T> virtual set(T v) = 0; // this would solve all my problems, if only it were legal.
};

template <class T>
class number : public element
{
T val;
public:
void print() {cout << "number is " << val << endl;}
void set(T v) {val = v;}
};

// That's the best I can do!
template <class T>
void myset(T v, element *ptr)
{
// There is a kink in the template: the compiler checks the T type by the value of v, that in this case is an integer:
// cout << "Type name for the template is: " << typeid(T).name() << endl;
// cout << "Type name for an integer is: " << typeid(int).name() << endl;

if (typeid(*ptr) == typeid(number<double>))
{
((number<double> *) ptr) -> set(7);
return;
}
else if (typeid(*ptr) == typeid(number<float>))
{
((number<float> *) ptr) -> set(7);
return;
}
// add other types... (tedious)
else
{
cout << "type not supported" << endl;
}
}

int main()
{
vector <element *> lst; // list of heterogeneous templatized objects
lst.push_back(new number<float>);
lst.push_back(new number<double>);

lst[0] -> print();

//((number<float> *) lst[0]) -> set(7); it's correct but it requires I know the type when I call it (tedious)

myset(7, lst[0]); // may be inefficient, but it works (for the types which are explicitly supported)

// cast_to_what_the_pointer_actually_points_to <lst[0]> -> set(7); // that's what I'd like to do: a downcast function which checks the object type and returns the correct pointer would be able to call any class method...

lst[0] -> print();
}

最佳答案

你快到了。您需要有一个模板化的 set 方法,该方法使用 typeid 和指向其参数的 void * 指针调用私有(private)虚方法,从而允许覆盖决定如何处理它:

class element
{
virtual void set_impl(const std::type_info &, const void *) = 0;
public:
template <class T> void set(T v) { set_impl(typeid(v), &v); }
};

以及如何编写 set_impl 的示例:

template <class T>
class number : public element
{
T val;
void set_impl(const std::type_info &ti, const void *pv) {
if (ti == typeid(T)) {
val = *static_cast<const T *>(pv);
} else {
throw std::invalid_argument("incorrect type to set()");
}
}
};

这类似于 Boost.Any 采取的方法.

关于c++ - 自动向下转换指向派生对象的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17784783/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com