C++ Class 继承,未定义的引用

C++ Class Inheritance, Undefined Reference

我正在创建二维形状的 class 层次结构。底class是一个四边形,梯形和平行四边形继承四边形,矩形继承平行四边形,正方形继承矩形。我正在尝试测试我的 classes,因此我可以更正我发现的任何错误,但我收到了编译错误。这是与我的错误有关的相关部分:

Shapes.h:

#ifndef Shapes_h
#define Shapes_h

class Point {
public:
  Point();
  Point(int, int);
  int getX();
  int getY();
  void setValues();
private:
  int x;
  int y;
};

class Quadrilateral {
public:
    Quadrilateral();
    Quadrilateral(Point, Point, Point, Point);
    void print();
private:
  Point point1;
  Point point2;
  Point point3;
  Point point4;
};

class Parallelogram : public Quadrilateral {
public:
  Parallelogram();
  Parallelogram(Point, Point, int);
  void print();
private:
  Point point1;
  Point point2;
  Point point3;
  Point point4;
};

class Trapezoid : public Quadrilateral {
public:
  Trapezoid();
  Trapezoid(Point, Point, int, int);
  void print();
private:
  Point point1;
  Point point2;
  Point point3;
  Point point4;
};

class Rectangle : public Parallelogram {
public:
  Rectangle();
  Rectangle(Point, int, int);
  void print();
private:
  Point point1;
  Point point2;
  Point point3;
  Point point4;
};

class Square : public Rectangle {
public:
  Square();
  Square(Point, int);
  void print();
private:
  Point point1;
  Point point2;
  Point point3;
  Point point4;
};

#endif /* Shapes_h */

Point.cpp:

#include "Shapes.h"
#include <iostream>
using namespace std;

Point::Point() {
  this->x = 0;
  this->y = 0;
}

Point::Point(int x, int y){
  this->x = x;
  this->y = y;
}

int Point::getX(){
  return this->x;
}

int Point::getY(){
  return this->y;
}

Square.cpp:

#include "Shapes.h"
#include <iostream>
using namespace std;

Square::Square(Point a, int len):Rectangle(a, len, len) {

}

Rectangle.cpp(文件给我错误):

#include "Shapes.h"
#include <iostream>
using namespace std;

Rectangle::Rectangle(Point a, int len, int height):Parallelogram(a, Point(a.getX(), a.getY()+height), len) {

}

Parallelogram.cpp:

#include "Shapes.h"
#include <iostream>
using namespace std;

Parallelogram::Parallelogram(Point a, Point b, int len):Quadrilateral(a, b, Point(a.getX()+len,a.getY()), Point(b.getX()+len, b.getY())) {

}

Quadrilateral.cpp:

#include "Shapes.h"
#include <iostream>
using namespace std;

Quadrilateral::Quadrilateral(){
  this->point1 = Point(0,0);
  this->point2 = Point(0,1);
  this->point3 = Point(1,0);
  this->point4 = Point(1,1);
}

Quadrilateral::Quadrilateral(Point a, Point b, Point c, Point d) {
  this->point1 = a;
  this->point2 = b;
  this->point3 = c;
  this->point4 = d;
}

测试驱动程序:

#include "Shapes.h"
#include <iostream>
using namespace std;

int main() {
  Square square = Square(Point(1,1),2);
  square.print();
  return 0;
}

命令行编译错误:

g++ -Wall -Wextra -c *.cpp
g++ -o *.o
/usr/bin/ld: Rectangle.o: in function `Rectangle::Rectangle(Point, int, int)':
Rectangle.cpp:(.text+0x74): undefined reference to `Parallelogram::Parallelogram(Point, Point, int)'
collect2: error: ld returned 1 exit status

因此,据我所知,Square 能够成功调用 Rectangle 构造函数,但 Rectangle 无法调用 Parallelogram。

您可以通过以下方式改进您的代码:

  • 使用在继承中为四边形声明的点数。平行四边形、梯形、矩形和正方形中定义的永远不会被使用或正确初始化。
  • 删除不需要的默认构造函数。您也可以轻松地不declare/define它们,然后它们将被隐藏。
  • 每个 class
  • 的专用头文件
  • 如果包含一个还定义了 class Point
  • 的库,使用命名空间会更容易
  • 使用自动

Point.hpp

#ifndef Point_h
#define Point_h

namespace Shape {
  class Point {
    public:
    Point();
    Point(int x, int y);
    int getX();
    int getY();
    std::string toString();
    
    private:
    int x;
    int y;
  };
}

#endif /* Point_h */

Point.cpp

#include <Point>
#include <iostream>
#include <sstream>
#include <string>

namespace Shape {
  Point::Point() {
    this -> x = 0;
    this -> y = 0;
  }
  Point::Point(int x, int y) {
    this -> x = x;
    this -> y = y;
  }
  int Point::getX() {
    return this -> x;
  }
  int Point::getY() {
    return this -> y;
  }
  std::string Point::toString() {
    std::ostringstream oss;
    oss << "Point(";
    oss << x;
    oss << ", ";
    oss << y;
    oss << ")";
    return oss.str();
  }
}

Quadrilateral.hpp

#ifndef Quadrilateral_h
#define Quadrilateral_h

namespace Shape {
  class Quadrilateral {
    public:
    Quadrilateral();
    Quadrilateral(Point a, Point b, Point c, Point d);
    void print();
    
    protected:
    Point point1;
    Point point2;
    Point point3;
    Point point4;
  };
}
#endif /* Quadrilateral_h */

Quadrilateral.cpp

#include <Quadrilateral>
#include <iostream>

namespace Shape {
  Quadrilateral::Quadrilateral() {
    this -> point1 = Point(0, 0);
    this -> point2 = Point(0, 1);
    this -> point3 = Point(1, 0);
    this -> point4 = Point(1, 1);
  }
  Quadrilateral::Quadrilateral(Point a, Point b, Point c, Point d) {
    this -> point1 = a;
    this -> point2 = b;
    this -> point3 = c;
    this -> point4 = d;
  }
  void Quadrilateral::print() {
      std::cout<<"Quadrilateral: "<<point1.toString()<<", "<<point2.toString()<<", "<<point3.toString()<<", "<<point4.toString()<<std::endl;
  }
}

Parallelogram.hpp

#ifndef Parallelogram_h
#define Parallelogram_h

#include <Quadrilateral>
#include <iostream>

namespace Shape {
  class Parallelogram: public Quadrilateral {
    public:
    Parallelogram() = delete;
    Parallelogram(Point a, Point b, int len);
    void print();
  };
}

#endif /* Parallelogram_h */

Parallelogram.cpp

#include <Parallelogram>
#include <iostream>

namespace Shape {
    Parallelogram::Parallelogram(Point a, Point b, int len): Quadrilateral(a, b, Point(a.getX() + len, a.getY()), Point(b.getX() + len, b.getY())) {}

    void Parallelogram::print() {
      std::cout<<"Parallelogram: "<<point1.toString()<<", "<<point2.toString()<<", "<<point3.toString()<<", "<<point4.toString()<<std::endl;
    }
}

Trapezoid.hpp

#ifndef Trapezoid_h
#define Trapezoid_h

#include <Quadrilateral>
#include <iostream>

namespace Shape {
  class Trapezoid: public Quadrilateral {
    public:
    Trapezoid() = delete; 
    Trapezoid(Point a, Point b, int len1, int len2);
    void print();
  };
}
#endif /* Trapezoid_h*/

Trapezoid.cpp

#include <Trapezoid>
#include <iostream>

namespace Shape {
  Trapezoid::Trapezoid(Point a, Point b, int len1, int len2): Quadrilateral(a, Point(a.getX(), a.getY()+len1), b, Point(b.getX(), b.getY()+len2)) {}

  void Trapezoid::print() {
      std::cout<<"Trapezoid: "<<point1.toString()<<", "<<point2.toString()<<", "<<point3.toString()<<", "<<point4.toString()<<std::endl;
  }
}

Rectangle.hpp

#ifndef Rectangle_h
#define Rectangle_h

#include <Parallelogram>

namespace Shape {
  class Rectangle: public Parallelogram {
    public:
    Rectangle() = delete; 
    Rectangle(Point a, int len, int height);
    void print();
  };
}

#endif /* Rectangle_h*/

Rectangle.cpp

#include <Rectangle>
#include <iostream>

namespace Shape {
  Rectangle::Rectangle(Point a, int len, int height): Parallelogram(a, Point(a.getX(), a.getY() + height), len) {}

  void Rectangle::print() {
      std::cout<<"Rectangle: "<<point1.toString()<<", "<<point2.toString()<<", "<<point3.toString()<<", "<<point4.toString()<<std::endl;
  }
}

Square.hpp

#ifndef Square_h
#define Square_h

#include <Rectangle>

namespace Shape {
  class Square: public Rectangle {
    public:
    Square() = delete;
    Square(Point a, int len);
    void print();
  };
}

#endif /* Square_h*/

Square.cpp

#include <Square>
#include <iostream>

namespace Shape {
  Square::Square(Point a, int len): Rectangle(a, len, len) {}

  void Square::print() {
      std::cout<<"Square: "<<point1.toString()<<", "<<point2.toString()<<", "<<point3.toString()<<", "<<point4.toString()<<std::endl;
  }
}

main.cpp

#include <Square>
#include <Trapezoid>

int main()
{
  auto square1 = Shape::Square(Point(1,1),2);
  square1.print();
  auto trapezoid1 = Shape::Trapezoid(Point(1,1), Point(2,0), 3, 5);
  trapezoid1.print();

  return 0;
}

输出将是:

Square: Point(1, 1), Point(1, 3), Point(3, 1), Point(3, 3)
Trapezoid: Point(1, 1), Point(1, 4), Point(2, 0), Point(2, 5)

此处的问题与给出的编译命令有关。 -o 标志允许您命名输出的可执行文件。因为您没有证明名称,所以它使用 *.o 中提供的第一个文件并覆盖它,将其用作文件名。因为它被覆盖了,它破坏了其他文件的编译。此处的解决方案是提供名称或删除 -o 标志。