如何通过交叉广播恢复接口
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
.
一垒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 byT
.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 aT
object, and if only one object of typeT
is derived from the sub-object pointed (referred) to byv
, the result is a pointer (an lvalue referring) to thatT
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 typeT
, that is unambiguous and public, the result is a pointer (an lvalue referring) to theT
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
.