检查两个(智能)指针是否指向同一派生类

时间:2017-10-19 19:50:52

标签: c++ c++11

假设我有一个基础抽象类B和一百个派生自D1 ... D100的类。我还有两个(智能)指针unique_ptr<B> p1, p2;,指向两个不同的类型DiDj的实例。我想知道他们指向的对象是否具有相同的类型(即i是否等于j)。有一个简单的方法吗?

3 个答案:

答案 0 :(得分:7)

您可以使用RTTI typeid,但通常情况下,必须使用dynamic_cast是一个糟糕的设计,因为它可能违反了liskov替换原则

std::unique_ptr<B> p1, p2;
if(typeid(*p1) == typeid(*p2)) // correction by Justin

使用namehash_code

之类的东西

答案 1 :(得分:5)

检查C ++ RTTI相对昂贵且繁琐:考虑在基类中添加事件标记,并检查该值。

enum class EventTag {
    A, B
};

struct EventBase {
    const EventTag tag;
    EventBase(EventTag tag) : tag(tag) {
    }
};

struct EventA : public EventBase {
    EventA() : EventBase(EventTag::A) {
    }
};

struct EventB : public EventBase {
    EventB() : EventBase(EventTag::B) {
    }
};

if (thisEvent->tag == thatEvent->tag) {
    // stuff
}

联盟而不是类层次结构也可以为你做。

答案 2 :(得分:0)

这可能看起来有点复杂,但它可以确保您在比较方面的可操作性。这种方法在可维护性方面有更多的开销,但它将确保正确的比较,而不会在时间执行方面执行过多的开销。

#include <string>
#include <iostream>
#include <memory>

class AbstractBase {
public:
    enum DerivedTypes {
        DERIVED_A,
        DERIVED_B
    };

protected:
    DerivedTypes type_;

public:
    explicit AbstractBase( const DerivedTypes type ) : type_( type ) {}

    virtual void print() = 0;

    DerivedTypes getType() const {
        return type_;
    }   

    bool operator==( const AbstractBase& other ) {
        return this->type_ == other.getType();
    }
};

class DerivedA : public AbstractBase {
public:
    const int x = 5;

public:
    explicit DerivedA( const DerivedTypes type = DerivedTypes::DERIVED_A ) : AbstractBase( type ) {}

    virtual void print() override {
        std::cout << "DerivedA\n";
    } 
};

class DerivedB : public AbstractBase {
public:
    const float y = 1.5f;

public:
    explicit DerivedB( const DerivedTypes type = DerivedTypes::DERIVED_B ) : AbstractBase( type ) {}

    virtual void print() override {
        std::cout << "DerivedB\n";
    }
};

int main() {
    std::unique_ptr<DerivedA> p1 = std::make_unique<DerivedA>( DerivedA() );
    std::unique_ptr<DerivedB> p2 = std::make_unique<DerivedB>( DerivedB() );

    p1->print();
    p2->print();

    if ( *p1 == *p2  ) {
        std::cout << "pointers are the same\n";
    } else {
        std::cout << "pointers are not the same\n";
    }

    std::unique_ptr<DerivedA> p3 = std::make_unique<DerivedA>( DerivedA() );
    std::unique_ptr<DerivedA> p4 = std::make_unique<DerivedA>( DerivedA() );

    p3->print();
    p4->print();

    if ( *p3 == *p4 ) {
        std::cout << "pointers are the same\n";
    } else {
        std::cout << "pointers are not the same\n";
    }

    return 0;
}

此处可维护性的增加成本取决于有多少派生类。如果从一开始就使用这种设计模式,那么很容易遵循。如果必须修改可计算数量的类,则需要花费一些时间和精力来修改现有的代码库。

这里的想法是抽象基类保留派生类型的内部变量,具有它的派生类型&amp;一个比较类型的重载==比较运算符。构造函数被强制采用其枚举类型以及所有派生类型。我还默认了派生类型,因此每次实例化类对象时都不必将它传递给它们的构造函数。这是可维护性的开销。

比较指针 - 多个派生类型的智能指针时,这种简单性就会发挥作用。当您查看上面的主函数时,您可以看到它非常简单,可以取消引用智能指针,基类的重载==运算符可以处理业务。

如果确实需要使用operator==()来实际比较类之间的数值差异,那么可以修改它以在基类中使用公共方法来比较类型并返回bool而不是重载运算符。