gpt4 book ai didi

c++ - 使用派生类的模板参数的抽象基类

转载 作者:行者123 更新时间:2023-11-30 05:23:55 26 4
gpt4 key购买 nike

我有一个提供纯虚拟接口(interface)的基类。我需要它来将指向派生类对象的指针存储在指向基类的指针列表中。

派生类是使用模板机制创建的。现在的问题是,如果我想要一个虚拟接口(interface)来返回一个只有派生类知道的类型,我还需要将它作为模板参数传递。这是困境开始的地方......

template <typename ITEM>
class base {
public:
virtual ITEM* get() = 0;
};

template <typename ITEM>
class derived : public base<ITEM>{
public:
ITEM* get() {...};
};

但是当在 base 中使用模板时,即使在创建基指针列表时我也需要知道这一点:

base* myList[10] = {derived1, derived2,...}

当然,当我定义我的列表时,我并不知道那个类型。所以我需要以某种方式摆脱基类中的模板。

编辑:摆脱了这种方法,因为它根本不是一种有用的方法。所以这个问题没有解决方案。

最佳答案

您编写的代码无效;没有一个base然后像在 Java 中一样参数化的类型,但是有一些 base<T>类型。有一种方法可以获得真正通用对象的包装器,称为“类型删除”。例如,它用于 boost::any 的实现。

基本上,您有一个带有虚函数的非模板基类,然后创建一个实现它们的模板派生类。请注意,如果您想要一个 base 的数组,此处显示的简化 版本有效。对象,因为 base具有纯虚函数,因此无法实例化(,因为派生类型的 T 成员将被切掉)。

struct base;
template<typename T>
struct derived;

struct base {
virtual ~base();

// In this class we don't know about T, so we cannot use it
// Other operations that delegate to the derived class are possible, though
virtual std::size_t sizeofT() const = 0;
virtual const std::type_info& typeofT() const = 0;

// Since all you want is a pointer in "get", you could write it as a void*
virtual void* getPtr() = 0;

// Otherwise, we can implement this template function here that calls the virtual.
// Note that function templates cannot be virtual!
template<typename U>
U& getAs() {
// Verify that the type is the _same_ (no up/downcasts allowed)
// std::bad_cast is thrown here if U is not the same T used to build this object
derived<U>& meAsU = dynamic_cast<derived<U>&>(*this);
return meAsU.obj;
}
};

template<typename T>
struct derived : public base {
T obj;
// A couple of ctors to initialize the object, and the default copy/move ctors/op=
virtual ~derived();
derived(const T& o) : obj(o) {}
derived(T&& o) : obj(std::move(o)) {}

std::size_t sizeofT() const override {
return sizeof(T);
}
const std::type_info& typeofT() const override {
return typeid(T);
}
void* getPtr() override {
return static_cast<void*>(&obj);
}
};

如果你想使用 base直接作为变量键入,或者在数组或容器( vector 、列表等)中键入,您需要动态分配 - 没有两种解决方法。您有两种选择,它们在动态分配责任的位置上有所不同:

  • 如果您限制自己使用指向 base指针数组,则可以使用上述解决方案。 .例如。 std::unique_ptr<base> 的数组.指向的对象类型为 derived<something> .

    base err1; // Error, abstract class (what would it contain?)
    base err2 = derived<int>(2); // Still abstract class, and the int would be sliced off
    std::unique_ptr<base> ok(new derived<int>(3)); // Works

    std::vector<std::unique_ptr<base>> objects;
    objects.push_back(std::make_unique(new derived<int>(5)));
    objects.push_back(std::make_unique(new derived<std::string>(2)));
    int& a = objects[0].getAs<int>(); // works
    std::string& b = objects[1].getAs<std::string>(); // works too
    std::string& bad = objects[1].getAs<double>(); // exception thrown
  • 否则,您将不得不在基类/派生类中实现动态分配。这就是像 boost::any 或 std::function 这样的类所做的。最简单的any object 将只是 base 的 unique-ptr 的包装器我在这里展示的类,以及运算符的适当实现等。然后,您可以拥有一个类型为 any x = y; 的变量。并且该类将在其构造函数中执行所需的 new derived<Y>(y)。需要。

关于c++ - 使用派生类的模板参数的抽象基类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38956584/

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