我正在使用复合设计模式,我想从复合类中克隆我的对象。我试图在我的组件类中创建一个通用克隆方法,但是当我尝试将我的对象的具体类型发送到通用(模板)方法时,' typeof'和' typeid'返回抽象类类型。所以,当我尝试使用new typeof(object)时,我看到了错误
"抽象类类型的新表达式无效'组件'"。
我的编译器是MigGW 32位。
由于我无法知道对象的类型,因此我无法使用dynamic_cast。
我错误地使用typeof / typeid还是应该使用其他关键字来了解具体的对象类型?
#include <iostream>
#include <vector>
#include <typeinfo>
class Component
{
public:
template <typename Tdest> typename std::remove_cv<typename std::remove_pointer<Tdest>::type>::type* clone() const
{
typedef typename std::remove_cv<typename std::remove_pointer<Tdest>::type>::type NO_POINTER_NOR_CV;
return new typeof(NO_POINTER_NOR_CV)(*dynamic_cast<const NO_POINTER_NOR_CV*>(this));
}
virtual void manipulateComponents() = 0;
virtual void add(Component* comp) = 0;
protected:
std::vector<const Component*> _v;
};
class Leaf : public Component
{
void manipulateComponents() override { return; }
void add(Component* comp) override { return; }
};
class Composite : public Component
{
public:
void manipulateComponents() override
{
for(auto component : _v)
{
std::cout << typeid(component).name() << std::endl; // print PK9Component
component->clone<typeof(component)>();
/* ... */
}
}
void add(Component* comp) override { _v.push_back(comp); }
};
int main(int argc, char* argv[])
{
Component* l = new Leaf();
Component* c = new Composite();
Component* parent = new Composite();
parent->add(l);
parent->add(c);
parent->manipulateComponents();
}
答案 0 :(得分:3)
您没有使用typeid
获取派生类型的详细信息,因为您在指针上使用它。取消引用调用中的pionter以获取派生类型的名称。
更改
std::cout << typeid(component).name() << std::endl; // print PK9Component
// PK9Component seems indicate that it is a pointer to a Component.
到
std::cout << typeid(*component).name() << std::endl;
// ^^
答案 1 :(得分:3)
如果你想要一个克隆方法,你必须添加一个虚函数来返回它,如:
for alpha=1:100
fimplicit(@(x,y) x.^3 +x + (1+alpha)*y, [-10 10 -10 10])
hold on
end
hold off
struct A
{
virtual std::unique_ptr<A> clone() const = 0;
A() = default;
A(A const&) = default;
A(A&&) = default;
A& operator=(A&&) = default;
A& operator=(A const&) = default;
virtual ~A() = default;
};
struct B : A
{
std::unique_ptr<A> clone() const override
{
assert(typeid(*this) == typeid(B));
return std::make_unique<B>(*this);
}
};
保护(在运行时)不会导致assert
w / o覆盖B
方法。
C ++委员会正在研究A polymorphic value-type for C++,但这种情况暂时无法实现。
答案 2 :(得分:0)
克隆方法中的typeof
魔法数量不会为您提供非模板化类的子类类型。它可以为您提供实例化模板的类型,但是您的克隆方法唯一可能的实例化在您的基类中。子类化不会重新定义模板方法。
如果你真的想要,你可以在子类化中使用模板方法,如果你愿意使用“奇怪的重复模板模式”。有一个示例clone implementation on Wikipedia,我在这里引用:
// Base class has a pure virtual function for cloning
class Shape {
public:
virtual ~Shape() {};
virtual Shape *clone() const = 0;
};
// This CRTP class implements clone() for Derived
template <typename Derived>
class Shape_CRTP : public Shape {
public:
virtual Shape *clone() const {
return new Derived(static_cast<Derived const&>(*this));
}
};
// Nice macro which ensures correct CRTP usage
#define Derive_Shape_CRTP(Type) class Type: public Shape_CRTP<Type>
// Every derived class inherits from Shape_CRTP instead of Shape
Derive_Shape_CRTP(Square) {};
Derive_Shape_CRTP(Circle) {};
答案 3 :(得分:0)
使用CRTP,您可以:
template <typename Derived>
class IClonable
{
public:
virtual ~IClonable() = default;
std::unique_ptr<Derived> clone() const {
return std::unique_ptr<Derived>(cloneImpl());
}
protected:
virtual Derived* cloneImpl() const = 0;
};
template <typename Derived, typename Base>
class Clonable : public Base
{
public:
std::unique_ptr<Derived> clone() const { // Hide Base::clone to return static type.
return std::unique_ptr<Derived>(static_cast<Derived*>(cloneImpl()));
}
protected:
Clonable* cloneImpl() const { return new Derived{static_cast<const Derived&>(*this)}; }
};
然后:
class Component : public IClonable<Component>
{
public:
virtual void manipulateComponents() = 0;
virtual void add(const Component&) = 0;
};
class Leaf : public Clonable<Leaf, Component>
{
public:
void manipulateComponents() override {}
void add(const Component&) override {}
};
class Composite : public Clonable<Composite, Component>
{
public:
void manipulateComponents() override
{
for (const auto* component : _v)
{
auto cloned = component->clone(); // std::unique_ptr<Component>
/* ... */
}
}
void add(const Component& comp) override { _v.push_back(&comp); }
protected:
std::vector<const Component*> _v;
};
可能的用法:
Leaf l;
Composite c;
auto parent = c.clone(); // std::unique_ptr<Composite>
parent->add(l);
parent->add(c);
parent->manipulateComponents();