Dan Brenner
Dan Brenner

Reputation: 888

Subclass Constructors

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

Answers (6)

iammilind
iammilind

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

Neel Basu
Neel Basu

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

Joachim Isaksson
Joachim Isaksson

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

cdmh
cdmh

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 Points 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

Mike Seymour
Mike Seymour

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

Uchia Itachi
Uchia Itachi

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

Related Questions