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
标志。
我正在创建二维形状的 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
标志。