1

我在使用 C++ 中的子类时遇到问题。我有一个多边形类和一个三角形子类。我希望能够通过传递 Point* 的向量(这是一个自定义类)和通过传递三个 Point*s 的三角形来声明多边形。

我的理解是 Triangle 类的构造函数应该调用 Polygon 类的构造函数。

这是我到目前为止所拥有的:

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);
    }
};

但是,在 Triangle 构造函数的左括号上出现错误:

error: no matching function call to 'Polygon::Polygon()'

有人可以帮忙吗?

4

6 回答 6

4

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);
}
于 2013-08-03T15:42:48.617 回答
2

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.

于 2013-08-03T15:43:54.087 回答
1

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.

于 2013-08-03T15:40:35.457 回答
1

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)
    {
    }
};
于 2013-08-03T15:41:58.753 回答
1

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});
于 2013-08-03T15:42:39.910 回答
1

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.

于 2013-08-03T15:43:52.180 回答