缩小指针构件的子类中派生的类

问题描述 投票:0回答:1

我有一个类层次结构在两个破 - 高层次的对象,而低级别和热插拔连接接口。连接对象形成一个类层次结构,其中,每个增加了更多的功能,以该连接。同样的,高层次的类层次结构需要逐步更好的连接。

该连接对象如下所示:

class BaseConnection {
    virtual void a() = 0;
};
class BetterConnection : public BaseConnection {
    virtual void b() = 0;
}
class BestConnection : public BetterConnection {
    virtual void c() = 0;
}

这是我在写高级别对象尝试

struct Base {
protected:
    // This type is correct for `Base`, but `Better` and `Best` need access to a more derived type.
    unique_ptr<BaseConnection> const m_conn;
public:
    Base(unique_ptr<BaseConnection> conn) : m_conn(std::move(conn));
    void do_a_twice() {
        auto& conn = *m_conn;
        conn.a(); conn.a();
    }
};
struct Better : public Base {
    Better(unique_ptr<BetterConnection> conn) : Base(std::move(conn));
    void do_b_twice() {
        auto& conn = dynamic_cast<BetterConnection&>(*m_conn);
        conn.b(); conn.b();
    }
};
struct Best : public Better {
    unique_ptr<BetterConnection> conn;
    Better(unique_ptr<BetterConnection> conn) : Better(std::move(conn));
    void do_c_twice() {
        auto& conn = dynamic_cast<BestConnection&>(*m_conn);
        conn.b(); conn.b();
    }
};

所以,我的问题:

  1. 有没有办法实现这个没有dynamic_cast
  2. 难道我就在想这会带来使用运行时类型信息的运行时开销?
  3. 它是安全的在这里使用reinterpret_cast
c++ polymorphism dynamic-cast
1个回答
0
投票

在我看来,围绕你的Connection类型的抽象正在事情变得更加困难(而抽象应该把事情简单化)。

Connection类型为什么会有不同的成员?如果派生类Connection而不是推翻了BaseConnection,你可以依靠虚函数派遣做正确的事在运行时。例如

struct BaseConnection {                             
    virtual void connect() {                        
        cout << "BaseConnection::connect" << endl;  
    }                                               
};                                                  

struct BetterConnection : public BaseConnection {   
    void connect() override {                       
        cout << "BetterConnection::connect" << endl;
    }                                               
};                                                  

struct BestConnection : public BetterConnection {   
    void connect() override {                       
        cout << "BestConnection::connect" << endl;  
    }                                               
};                                                  

class X {                                           
public:                                             
    X(std::unique_ptr<BaseConnection> connection)   
        : connection_(std::move(connection))        
    {                                               
        connection_->connect();                     
    }                                               

private:                                            
    std::unique_ptr<BaseConnection> connection_;    
};                                                  

int main() {                                        
    X(std::make_unique<BaseConnection>());          
    X(std::make_unique<BetterConnection>());        
    X(std::make_unique<BestConnection>());          
}                                                   

如果Connection类型有不同的方法,因为他们真正在执行不同的操作,那么它引出了一个问题,如果继承是使用正确的抽象。

也许你可以添加你重写“做正确的事”为每个衍生Connection虚方法。然后,更高级别的类只需要调用此方法之一,它可以在没有铸造完成。

一般来说,如果你发现自己不得不使用dynamic_cast在运行时执行类型检查,这可能意味着该接口的设计并不适合多态性的初衷。我会重新考虑你的对象之间的接口,并尝试看看是否有一种方式来获得你想要的东西,而不必上溯造型。


编辑:使用类型特征

根据您的意见,好像你可能需要您的更高级别的对象比我原来提供的答案更多的定制。从本质上说,我觉得你想要做什么在您管理基础是什么类型Connection是的情况下,提供更高层次的功能,不同的实现。

一种常见的方式做到这一点(STL的,以及如何做到这一点)是通过操作与类型特征超载。为了说明,首先描述底层的连接对象的性状的几种类型。

struct base_connection_tag {};                               
struct better_connection_tag : public base_connection_tag {};
struct best_connection_tag : public better_connection_tag {};

然后我们可以将它们添加到Connection类。

struct BaseConnection {                               
    virtual void a() {                                
        cout << "BaseConnection::a()" << endl;        
    }                                                 

    using connection_category = base_connection_tag;  
};                                                    

struct BetterConnection : public BaseConnection {     
    virtual void b() {                                
        cout << "BetterConnection::b()" << endl;      
    }                                                 

    using connection_category = better_connection_tag;
};                                                    

struct BestConnection : public BetterConnection {     
    virtual void c() {                                
        cout << "BestConnection::c" << endl;          
    }                                                 

    using connection_category = best_connection_tag;  
};                                                    

按照惯例,connection_traits回声的Connection类的嵌套的typedef

template <typename ConnectionT>                                           
struct connection_traits {                                                
    using connection_category = typename ConnectionT::connection_category;
};                                                                        

最后,我们可以使用运算符重载来决定采用这样的模式在某些更高级别的类来调用它的实现(或类):

template <typename T>                                                 
class Dispatch                                                        
{                                                                     
public:                                                               
    Dispatch(std::unique_ptr<T> connection)                           
        : connection_(std::move(connection))                          
    {}                                                                

    void operator()() {                                               
        connect(typename connection_traits<T>::connection_category());
    }                                                                 

private:                                                              

    void connect(base_connection_tag) {                               
        connection_->a();                                             
    }                                                                 

    void connect(better_connection_tag) {                             
        connection_->b();                                             
    }                                                                 

    void connect(best_connection_tag) {                               
        connection_->c();                                             
    }                                                                 

    std::unique_ptr<T> connection_;                                   
};                                                                    

()操作被调用时,Dispatch类调用的使用基础connectconnection_traitsConnection方法之一。

由于所有类型都在编译时已知的Dispatch类就知道要在编译期间调用哪个基方法。没有dynamic_cast需要确定哪种类型的举行。

虽然我只用一个模板类来实现更高阶的功能,你可以切实使用多个非模板类做同样的事情,使用connection_traits和功能参数重载每个启用/禁用功能。

© www.soinside.com 2019 - 2024. All rights reserved.