问题
I am creating an application that allows a user to define dimensions for different shapes and returns the area to the user using the dimensions they specified.
My base class is Shape. Derived classes are Triangle, Circle, Square and Rectangle.
I have created an array of Shape in the hope of creating and storing instances of any of the derived classes in the array during runtime.
Shape** shape = new Shape*[TOTAL_SHAPES];
shape[i] = new Circle(radius);
I have managed this, however I am unable to access the instantiated classes methods. Sorry if this is a stupid question I am fairly new to C++.
回答1:
Let's assume your types had the following definition
class Shape {
public:
void Method1() { ... }
};
class Circle : public Shape {
void Method2() { ... }
}
With this definition you could access methods on Shape
by doing the following
shape[i]->Method1();
In this context though it wouldn't be possible to access Method2
though because the compiler only knows about Shape
, not Circle
.
shape[i]->Method2(); // Error!
回答2:
You have three options:
- Make
Shape
an abstract base class and callvirtual
methods that are members ofShape
- Use
static_cast
to cast from aShape*
to aCircle*
, and call methods through that. - Use
dynamic_cast
to cast from aShape*
to aCircle*
, and call methods through that.
The first option is likely best in many cases. Among other reasons, you almost surely need to have a virtual
destructor (which can be a by-product of making Shape
an ABC), and you may prefer to not have to know what type of object is being pointed to, rather you'd like to simply call methods on whatever it may be. If you can use this idiom, use it.
The second option is dangerous. You must absolutely know that the object being pointed to is a Circle
(or whatever) in order to use static_cast
, else you will get Undefined Behavior.
The third option is only possible if your class is polymorphic, which means Shape
must have at least one virtual
method. You surely should have a virtual
destructor, and this would serve that purpose.
回答3:
How about that:
shape[i]->aMethod();
回答4:
For starters, I highly recommend using a smart pointer wrapper instead of using raw pointers (especially if you are new to the language).
std::vector<std::shared_ptr<Shape>> shapes(TOTAL_SHAPES);
That will define a vector with an initial size of TOTAL_SHAPES
.
To the root of your problem, any method you wish to call using a Shape*
must be valid for Shape
, or you must do a risky downcast to the appropriate type. For example:
class Shape
{
public:
// constructors and other methods go here
virtual ~Shape() { } // virtual destructor
virtual void Draw() { } // virtual function to be used by derived classes
};
class Circle
{
public:
// ...
virtual ~Circle() { }
virtual void Draw() { } // override the virtual function
};
Then, in your application code,
std::vector<std::shared_ptr<Shape>> shapes(TOTAL_SHAPES);
shapes[0] = std::make_shared(new Circle);
shapes[0]->Draw(); // calls Circle::Draw
Note that depending on your usage, std::unique_ptr
may replace std::shared_ptr
.
来源:https://stackoverflow.com/questions/20912106/c-array-of-base-class-which-has-instances-of-derived-classes-stored-in-the-ele