Reputation: 888
I am having trouble working with subclasses in C++. I have a class for a Polygon and a subclass that is a Triangle. I would like to be able to declare a Polygon by passing a vector of Point* (which is a custom class) and a Triangle by passing three Point*s.
It is my understanding that the Triangle class constructor should call the constructor of the Polygon class.
This is what I have so far:
class Polygon
{
public:
vector<Point*> pts;
Polygon(vector<Point*> aPts) : pts(aPts) {};
};
class Triangle : public Polygon
{
public:
Triangle(Point* A, Point* B, Point* C)
{
vector<Point*> APts;
APts.push_back(A); APts.push_back(B); APts.push_back(C);
Polygon(APts);
}
};
However, on the opening bracket of the Triangle constructor I get the error:
error: no matching function call to 'Polygon::Polygon()'
Can somebody help?
Upvotes: 1
Views: 4561
Reputation: 69988
Constructor of the base class should be called from the subclass's constructor's initializer list. That's what causing compiler error in your code. Also the below syntax is valid, but it just creates a temporary object of Polygon
and destoys it:
Polygon(APts);
From design point of view, by copying vectors by value you are doing expensive operations.
Just don't do it. Have a no argument constructor and then later populate the constructor.
class Polygon
{
public:
vector<Point*> pts; // can be made protected as well
Polygon() {};
};
class Triangle : public Polygon
{
public:
Triangle(Point* A, Point* B, Point* C)
{
pts.push_back(A); pts.push_back(B); pts.push_back(C);
}
};
If you have support for C++11, then the same code can be wrote more elegantly.
class Polygon {
protected:
vector<Point*> pts;
public:
Polygon(std::initializer_list<Point*>& v) : pts(v) {}
};
class Triangle : public Polygon {
public:
Triangle (Point* p1, Point* p2, Point* p3) :
Polygon({p1, p2, p3}) {}
};
class Square : public Polygon {
public:
Square (Point* p1, Point* p2, Point* p3, Point* p4) :
Polygon({p1, p2, p3, p4}) {}
};
Usage:
Triangle t({x, y, z});
Square s({w, x, y, z});
Upvotes: 1
Reputation: 12904
You can have an addPoint()
function in your Polygon
class
class Polygon{
public:
vector<Point*> pts;
Polygon(){}/// < The default constructor
Polygon(vector<Point*> aPts) : pts(aPts) {}
void addPoint(Point* p){
pts.push_back(p);
}
};
class Triangle : public Polygon{
public:
Triangle(Point* A, Point* B, Point* C){// calls the default constructor
addPoint(A);
addPoint(B);
addPoint(C);
}
};
additionally, A Point
can be copied by value most of the time. I don't know why you are passing it by pointer.
Upvotes: 2
Reputation: 180887
You have to call the Polygon constructor as a part of your initializer list, which means that you need to build a function that initializes your vector;
class Triangle : public Polygon
{
// static method, not part of the object being constructed.
static vector<Point*> BuildVector(Point* A, Point* B, Point* C) {
vector<Point*> APts;
APts.push_back(A); APts.push_back(B); APts.push_back(C);
return APts;
}
public:
// Need to call Polygon's constructor before even entering our own;
Triangle(Point* A, Point* B, Point* C) : Polygon(BuildVector(A, B, C))
{
}
};
Note that by pushing the pointers into a vector without copying the objects, you'll risk not doing memory handling correctly (who will free the memory?), so you may want to use some type of smart pointer, or just pass the points as references into the constructor.
Upvotes: 1
Reputation: 3344
In your Polygon
class, you define a constructor taking an argument, vector
. In this case the compiler will not generate a default constructor, so you have to pass a Polygon
constructor a parameter.
In Triangle
, you define a constructor taking three parameters, but you don't call a constructor of Polygon
. The compiler tries to find a default constructor - one with no parameters - but can't find one, so emits an error.
You cannot call the Polygon
constructor at the end of the Triangle
constructor like you have written. Polygon
ctor must be executed before the `Triangle ctor.
Try adding a ctor to Polygon
that takes the three Point
s directly instead of in a vector
, like this
class Polygon
{
public:
vector<Point*> pts;
Polygon(Point* A, Point* B, Point* C) {
pts.push_back(A);
pts.push_back(B);
pts.push_back(C);
}
};
class Triangle : public Polygon
{
public:
Triangle(Point* A, Point* B, Point* C) : Polygon(A, B, C)
{
}
};
Upvotes: 1
Reputation: 254431
The base class has to be initialised before the derived class's constructor body; if the constructor needs arguments, then these must be supplied in the initialiser list:
Triangle(Point* A, Point* B, Point* C) :
Polygon({A,B,C})
{}
Note that this uses C++11 syntax to create a temporary vector; if you're stuck in the past then it's a bit more complicated:
static std::vector<Point*> make_points(Point* A, Point* B, Point* C) {
std::vector<Point*> points;
points.push_back(A);
points.push_back(B);
points.push_back(C);
}
Triangle(Point* A, Point* B, Point* C) :
Polygon(make_points(A,B,C))
{}
or it might be easier (but potentially more error-prone) to give the base class a default constructor, and then populate the vector in the derived class constructor:
// In Polygon
Polygon() {} // constructed with no points
// pts must be "public" or "protected"
// In Triangle
Triangle(Point* A, Point* B, Point* C) {
pts.push_back(A);
pts.push_back(B);
pts.push_back(C);
}
Upvotes: 4
Reputation: 5315
It is trying to call the default constructor of Polygon
class, but since you have your own constructor in place the default empty constructor doesn't exist anymore. Hence, you will have to call the Polygon's
constructor with proper arguments or define an empty constructor.
Also, you can't the Polygon's
constructor with the arguments like that, this has to be done in initialization list of Triangle
class constructor. It is such in order to make sure that the members of base
are properly initialized before derived
class object is created.
Upvotes: 1