dynamic_cast 和 typeid 的 c++ 多态性
c++ polymorphism with dynamic_cast and typeid
假设我有一个 parent class Shape
和两个 children class class Square
和
class Circle
.
在我的代码中的某个时刻,我做了类似的事情:
Shape* genericshape;
if(a_time_consuming_test()){
genericshape = new Square;
} else {
genericshape = new Cricle;
}
后来我想创建另一个圆形或方形,但我不想
打电话 a_time_consuming_test()
。那么我可以使用 typeid
或类似的东西吗
直接创建 "right" 形状?像 :
if(typeid(genericshape) == typeid(Square)){
Square newsquare;
} else {
Circle newcircle;
}
我想应该有那种解决方案,但这似乎没有
高效,因为那天我有第三个形状,比如 Triangle
,我会
需要检查 Shape
的每个 children。会不会是这样的
可能吗?
Shape* newshape(&genericshape);
我的意思是,newshape
会是与 child class 相同的指针吗
genericshape
?
编辑
查看其中一个答案,我应该指定 Shape
、Square
和 Circle
实际上是模板 class。
我相信您正在寻找的是一个简单的克隆功能,它不会克隆数据,只会克隆类型。所以你可以将这样的东西添加到 Shape
:
struct Shape
{
virtual std::unique_ptr<Shape> createEmptyObject() const = 0;
// The rest as before
}:
struct Circle
{
std::unique_ptr<Shape> createEmptyObject() const override
{ return std::make_unique<Circle>(/*ctor args here*/); }
// The rest as before
};
然后像这样使用它:
Shape* genericshape;
if(a_time_consuming_test()){
genericshape = new Square;
} else {
genericshape = new Cricle;
}
// ...
auto anotherShape = genericshape->createEmptyObject();
注意:如果您无法访问 C++14,则必须将 make_unique
替换为手动构造的 unique_ptr
:
return std::unique_ptr<Shape>(new Circle(/*ctor args here*/));
如果您准备编辑以下类型列表,每次添加新形状时:
using shapes = typelist<circle, rectangle>;
那么我认为以下解决方案应该可行(逐步解释):
shape* create(shape const * s)
{
return create_impl(shapes(), s);
}
其中 create_impl
和其他支持定义为:
template<typename T, typename ... Ts>
struct typelist{};
using shapes = typelist<circle, rectangle>;
template<typename T, typename ...Rest>
shape* create_impl(typelist<T, Rest...>, shape const *s)
{
if ( typeid(T) == typeid(*s) )
return new T();
else
return create_impl(typelist<Rest...>(), s);
}
template<typename T>
shape* create_impl(typelist<T>, shape const *s)
{
return typeid(T) == typeid(*s)? new T() : nullptr;
}
以后如果你添加一个新的形状,比如说triangle
,然后把它添加到类型列表中:
using shapes = typelist<circle, rectangle, triangle>;
那么一切都应该会恢复正常。没有其他代码更改。
当然,你应该使用智能指针而不是原始指针,但我想这是对上面代码的一个小修改。基本思想将保持不变。
假设我有一个 parent class Shape
和两个 children class class Square
和
class Circle
.
在我的代码中的某个时刻,我做了类似的事情:
Shape* genericshape;
if(a_time_consuming_test()){
genericshape = new Square;
} else {
genericshape = new Cricle;
}
后来我想创建另一个圆形或方形,但我不想
打电话 a_time_consuming_test()
。那么我可以使用 typeid
或类似的东西吗
直接创建 "right" 形状?像 :
if(typeid(genericshape) == typeid(Square)){
Square newsquare;
} else {
Circle newcircle;
}
我想应该有那种解决方案,但这似乎没有
高效,因为那天我有第三个形状,比如 Triangle
,我会
需要检查 Shape
的每个 children。会不会是这样的
可能吗?
Shape* newshape(&genericshape);
我的意思是,newshape
会是与 child class 相同的指针吗
genericshape
?
编辑
查看其中一个答案,我应该指定 Shape
、Square
和 Circle
实际上是模板 class。
我相信您正在寻找的是一个简单的克隆功能,它不会克隆数据,只会克隆类型。所以你可以将这样的东西添加到 Shape
:
struct Shape
{
virtual std::unique_ptr<Shape> createEmptyObject() const = 0;
// The rest as before
}:
struct Circle
{
std::unique_ptr<Shape> createEmptyObject() const override
{ return std::make_unique<Circle>(/*ctor args here*/); }
// The rest as before
};
然后像这样使用它:
Shape* genericshape;
if(a_time_consuming_test()){
genericshape = new Square;
} else {
genericshape = new Cricle;
}
// ...
auto anotherShape = genericshape->createEmptyObject();
注意:如果您无法访问 C++14,则必须将 make_unique
替换为手动构造的 unique_ptr
:
return std::unique_ptr<Shape>(new Circle(/*ctor args here*/));
如果您准备编辑以下类型列表,每次添加新形状时:
using shapes = typelist<circle, rectangle>;
那么我认为以下解决方案应该可行(逐步解释):
shape* create(shape const * s)
{
return create_impl(shapes(), s);
}
其中 create_impl
和其他支持定义为:
template<typename T, typename ... Ts>
struct typelist{};
using shapes = typelist<circle, rectangle>;
template<typename T, typename ...Rest>
shape* create_impl(typelist<T, Rest...>, shape const *s)
{
if ( typeid(T) == typeid(*s) )
return new T();
else
return create_impl(typelist<Rest...>(), s);
}
template<typename T>
shape* create_impl(typelist<T>, shape const *s)
{
return typeid(T) == typeid(*s)? new T() : nullptr;
}
以后如果你添加一个新的形状,比如说triangle
,然后把它添加到类型列表中:
using shapes = typelist<circle, rectangle, triangle>;
那么一切都应该会恢复正常。没有其他代码更改。
当然,你应该使用智能指针而不是原始指针,但我想这是对上面代码的一个小修改。基本思想将保持不变。