First base class
class Io_obj
{
public:
virtual Io_obj* clone() const=0;
virtual ~Io_obj(){}
};
First derived 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};}
};
Second base class
class Shape
{
public:
virtual void draw() const=0;
virtual ~Shape(){}
};
Second derived 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";}
};
main functions
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;
}
Dynamic cast failed. It seems that the object created by unique_ptr<Io_obj> my_obj{get_obj(x)}
is of type Io_obj
, which has no member function draw()
. How to make it work?
Code from Bjarne Stroustrup: the C++ programming language Ch22.2.4
To fix this, change:
template<typename T>
class Io : public Io_obj, T
to:
template<typename T>
class Io : public Io_obj, public T
Access specifiers must be written separately for each base type. In your case, second derivation was private
, as this is the default mode.
dynamic_cast<>
converts Io<T>
to T
, if they are connected with is-a relation, which is created by public inheritation. In case of private, dynamic_cast<>
will not work, because Io<T>
is not T
(private inheritance creates relation called "implemented in terms of" ).
Test: http://coliru.stacked-crooked.com/a/130c7768fb5b501d
Of course this code will also throw an std::runtime_error
, as you have not registered "factory" for square
type, but I guess you already know this :)
Some reference, perhaps ( 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
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.