如何通过交叉广播恢复接口

How to recover an interface through crosscast

一垒class

class Io_obj
{
public:
    virtual Io_obj* clone() const=0;
    virtual ~Io_obj(){}
};

先导出class

template<typename T>
class Io : public Io_obj,T
{
public:
    Io(){}
    Io(string& s){cout << s << '\n';}
    Io* clone() const override {return new Io{*this};}
    static Io* new_io(string& s){return new Io{s};}
};

二垒class

class Shape
{
public:
    virtual void draw() const=0;
    virtual ~Shape(){}
};

二次导出classes

class Circle : public Shape
{
public:
    Circle(){}
    Circle(string& s){cout << s << '\n';}
    void draw() const override{cout << "draw circle\n";}
};

class Triangle : public Shape
{
public:
    Triangle(){}
    Triangle(string& s){cout << s << '\n';}
    void draw() const override {cout << "draw triangle";}
};

主要功能

using io_circle = Io<Circle>;
using io_triangle = Io<Triangle>;
using Pf = function<Io_obj*(string&)>;

map<string,Pf> io_map{{"circle",&io_circle::new_io},{"triangle",&io_triangle::new_io}};

Io_obj* get_obj(string& s){
    if(auto f=io_map[s]) return f(s);
    throw runtime_error{"error: wrong type"};
}

int main(){
    vector<string> vs{"circle","triangle","square"};
    for(auto x:vs){
        unique_ptr<Io_obj> my_obj{get_obj(x)};

        if(auto sp=dynamic_cast<Shape*>(my_obj.get())){
            sp->draw();
        }else{
            throw runtime_error{"error: bad cast"};
        }
    }
    return 0;
}

动态转换失败。看来unique_ptr<Io_obj> my_obj{get_obj(x)}创建的对象是Io_obj类型的,没有成员函数draw()。如何让它发挥作用?

来自 Bjarne Stroustrup 的代码:C++ 编程语言 Ch22.2.4

要解决此问题,请更改:

template<typename T>
class Io : public Io_obj, T

至:

template<typename T>
class Io : public Io_obj, public T

必须为每个基本类型单独编写访问说明符。在您的情况下,二次推导是 private,因为这是默认模式。

dynamic_cast<>Io<T> 转换为 T,如果它们与 is-a 关系相连,该关系由 [=59 创建=] 继承。在私有的情况下,dynamic_cast<> 将不起作用,因为 Io<T> 不是 T(私有继承创建称为 [= 的关系57=]).

测试:http://coliru.stacked-crooked.com/a/130c7768fb5b501d

当然这段代码也会抛出一个std::runtime_error,因为你还没有为square类型注册"factory",但我想你已经知道了:)

一些参考,也许 (18.5.2 - dynamic_cast<T>(v)):

Otherwise, a run-time check is applied to see if the object pointed or referred to by v can be converted to the type pointed or referred to by T.

The run-time check logically executes as follows:

If, in the most derived object pointed (referred) to by v, v points (refers) to a public base class subobject of a T object, and if only one object of type T is derived from the sub-object pointed (referred) to by v, the result is a pointer (an lvalue referring) to that T object.

Otherwise, if v points (refers) to a public base class sub-object of the most derived object, and the type of the most derived object has a base class, of type T, that is unambiguous and public, the result is a pointer (an lvalue referring) to the T sub-object of the most derived object.

Otherwise, the run-time check fails.

The value of a failed cast to pointer type is the null pointer value of the required result type. A failed cast to reference type throws bad_cast.