声明一个没有专用化的基类模板来初始化派生类

Declaring a base class template without specialization to initialize derived class

提问人:John Wong 提问时间:7/14/2023 更新时间:7/14/2023 访问量:85

问:

根据某些参数,我需要使用两个派生类之一。我知道我可以声明基类并使用它来初始化派生类之一。当基类是基类模板时,我该怎么做?

下面是一个简化的方案:

template <class T>
class shape
{
}

class rectangleInt : public shape<int> 
{
}

class rectangleDouble : public shape<double> 
{
}

int main() {

    // I want to do the following
    shape<T> shape;
    if (args == int) {
        shape = rectangleInt();
    } else {
        shape = rectangleDouble();
    }


}

我必须在代码中更改哪些内容才能完成我想要的?

C++ 对象 OOP 模板

评论

0赞 JaMiT 7/14/2023
“我知道我可以声明基类并使用它来初始化派生类之一。”--这读错了。我不知道这是你的误解还是用词不当。我的猜测是,您的意思是(或误解)了诸如基类指针之类的东西可以指向派生类。
1赞 Richard Critten 7/14/2023
rectangleInt并且不共享一个公共基类,因为 和 是不同的类。rectangleDoubleshape<int>shape<double>
0赞 JaMiT 7/14/2023
“当基类是基类模板时,我该怎么做?”-- 描述示例代码中内容的更好方法是“基类是同一类模板的不同实例化”。这可能是你困惑的根源。让我看看我是否能找到一个合适的问题。
1赞 Pepijn Kramer 7/14/2023
你需要更清楚一点,你是否知道编译时的类型,那么你甚至不需要构建一些复杂的东西,只需在代码中编写你想要的类型。如果你确实需要在运行时选择一个实例,那么你的 shape<T> 类本身必须派生自一个抽象基类,比如说,你需要一个工厂方法,它返回一个shape_itfstd::unique_ptr<shape_itf>
0赞 JaMiT 7/14/2023
我没有找到真正的重复项(部分原因是我不清楚你打算问什么),但你可能会发现类模板专业化从不同的基类继承是否合法? 照明。如果您打算成为指针,请参阅指向抽象模板基类的指针? 答案中的关键语句是:“每个模板实例化都是一个单独的类。shape

答:

1赞 Mestkon 7/14/2023 #1

不幸的是,它们是不同的、独立的类,因此不能自动互换使用它们。shape<int>shape<double>

因此,您可以为所有模板创建另一个唯一的基类:

class abstract_shape { };

template<class T>
class shape : public abstract_shape { };

通过这种设计,您实际上可以将指针、所有类派生自 any 的变量存储在 类型的变量中。shape<T>abstract_shape*

abstract_shape* my_shape1 = &my_double_rect; 
abstract_shape* my_shape2 = &my_int_rect;

如果这不能解决问题或不适合设计,可以选择基于的解决方案:std::variant

using shape_ptr = std::variant<std::nullptr_t, shape<int>*, shape<double>*>;

shape_ptr my_shape1 = &my_double_rect;
shape_ptr my_shape2 = &my_int_rect;

第三种选择是单独存储派生自 和 的形状,然后模板化使用它们的函数:shape<int>shape<double>

std::vector<std::unique_ptr<shape<int>>> my_int_shapes;
std::vector<std::unique_ptr<shape<double>>> my_double_shapes;

template<class T>
auto do_something_with_shape(shape<T>* obj);

auto do_something_with_all_shapes() {
    for (auto& int_shape : my_int_shapes) {
        do_something_with_shape(int_shape.get());
    }

    for (auto& double_shape : my_double_shapes) {
        do_something_with_shape(double_shape.get());
    }
}

评论

0赞 John Wong 7/15/2023
谢谢。对于我的情况来说,解决方案非常优雅。我曾经遇到过一点问题,因为我没有提供完整的细节。该类有一个称为的结构体和一个函数。我收到了这个错误。对于我代码中的这一行,我很困惑。 是一个指针,但错误说它是非指针类型。std::variantshape_ptr = std::variant<std::unique_ptr<shape<int>>, std::unique_ptr<shape<double>>>;shape<T>FooFoo bar()error: base operand of '->' has non-pointer type 'shape_ptr' while ((foo = shape_ptr->bar())) {shape_ptr
0赞 John Wong 7/16/2023
in 是指针的名称。打错了字。shape_ptrwhile ((foo = shape_ptr->bar())) {
0赞 John Wong 7/16/2023
我解决了。为了后代,以防将来有人需要它,您可以像这样访问该功能std::get<std::unique_ptr<shape<int>>>(indexlr)->bar()
1赞 Mestkon 7/17/2023
如果您不知道 是否包含 a 或 a,那么您可能需要使用 .shape_ptrshape<int>shape<double>std::visitstd::visit([](auto& ptr) { return ptr->bar(); }, my_shape_ptr);
1赞 Mestkon 7/19/2023
如果所有有效都相同,那么我建议将其与模板分开。例如,在上面声明它为或某物。如果这是不可能的,一种替代方法是强制访问者也返回变体shape<T>::FooTshapeshape<T>shapeFoousing shapeFoo = std::variant<shape<int>::Foo, shape<double>::Foo>; std::visit([](auto& ptr) -> shapeFoo { return ptr->bar(); }, my_shape_ptr);