如何在不使用dynamic_cast< ...>()的情况下了解具体对象类型

时间:2018-02-02 18:46:38

标签: c++ c++14

我正在使用复合设计模式,我想从复合类中克隆我的对象。我试图在我的组件类中创建一个通用克隆方法,但是当我尝试将我的对象的具体类型发送到通用(模板)方法时,' 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();
}

4 个答案:

答案 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();