C++ Ostream 运算符重载 - 构建时奇怪的未定义引用
C++ Ostream Operator Overload - odd undefined reference when building
我正在编写有关 C++ 的教程,以真正深入研究它的 nitty-gritty,因为坦率地说,它是一种很棒且功能强大的语言。不过,我对它还是很陌生,我在为 ostream 运算符重载运算符时遇到了问题。
因为这是一个教程,所以我尽量使我的代码井井有条和模块化,以避免混淆。我的代码有 3 层:
- main.cpp - 运行练习。
- 练习。cpp/Exercises.h - 包含练习的静态函数。
- ComplexNumber.cpp/ComplexNumber.h - 表示复数 object 与教程一致。
Main 相当简单:一组对 Exercises::ExerciseName() 的调用。
Exercises.cpp:
#include "Exercises.h"
void Exercises::ComplexNumberClass() {
ComplexNumber c; /** Runs the blank constructor */
ComplexNumber c1(2, 3); /** Runs the args-filled constructor */
ComplexNumber c2 = c1; /** Runs the copy constructor */
c = c2;
cout << c1 << endl;
}
header 文件只有 header 作为 public static void 函数,即可调用和可执行函数。 ComplexNumber 文件是我认为的问题所在(如果我错了请纠正我):
ComplexNumber.cpp(没有构造函数和访问器):
#include "ComplexNumber.h"
using namespace ComplexNumbers;
using namespace std;
ostream& operator<< (ostream& out, ComplexNumber& num){
out << "(" << num.GetReal() << ", " << num.GetImaginary() << ")";
return out;
}
const ComplexNumber &ComplexNumber::operator=(const ComplexNumber &num) {
cout << "Using assignment operator override" << endl;
real = num.real;
imaginary = num.imaginary;
return *this;
}
ComplexNumber.h:
#ifndef OPERATOROVERLOADING_COMPLEXNUMBER_H
#define OPERATOROVERLOADING_COMPLEXNUMBER_H
#include <iostream>
using namespace std;
namespace ComplexNumbers {
class ComplexNumber {
private:
double real;
double imaginary;
public:
ComplexNumber();
ComplexNumber(double real, double imaginary);
ComplexNumber(const ComplexNumber &num);
const ComplexNumber &operator=(const ComplexNumber &num);
double GetReal() const {
return real;
}
double GetImaginary() const {
return imaginary;
}
};
ostream &operator<<(ostream& out, ComplexNumber& num);
}
#endif //OPERATOROVERLOADING_COMPLEXNUMBER_H
当我构建它时,它告诉我我有一个“对 'cave_of_programming::operator<<(std::ostream&, cave_of_programming::ComplexNumber&)' 的未定义引用。方法 headers 匹配,我正在使用 Jetbrains CLion 构建。
我的研究表明问题出在链接器上,但我查看了我的 CMakeLists.txt 并发现它正在链接所有相应的文件。
SOURCE_FILES main.cpp Exercises.cpp Exercises.h ComplexNumbers/ComplexNumber.cpp ComplexNumbers/ComplexNumber.h
有人知道为什么这不起作用吗?我错过了什么?
问题是您在 class 中定义了 ostream &operator<<(ostream& out, ComplexNumber& num)
。这对编译器没有多大意义,因为它知道在获取 ostream 对象和某种类型的 class 时覆盖 operator<<
,
但是你实现它的方式,它得到了 ostream、一个 ComplexNumber 和另一个 ComplexNumber 作为 'this' 参考。
为了正确重载二元运算符,您有两个选择:
在class中定义运算符,只给它ostream作为参数
class ComplexNumber
{
...
ostream &operator<<(ostream& out) const;
};
或者在class之外定义运算符,并给它两个参数:
class ComplexNumber
{
...
};
ostream &operator<<(ostream& out, const ComplexNumber& num);
请注意,在第二个实现中,如果要访问任何私有成员,则需要将函数添加为 class 的友元。
另请注意,最好像我在示例中那样在此处使用 const,否则您将无法在 const ComplexNumbers 上使用运算符。
我正在编写有关 C++ 的教程,以真正深入研究它的 nitty-gritty,因为坦率地说,它是一种很棒且功能强大的语言。不过,我对它还是很陌生,我在为 ostream 运算符重载运算符时遇到了问题。
因为这是一个教程,所以我尽量使我的代码井井有条和模块化,以避免混淆。我的代码有 3 层:
- main.cpp - 运行练习。
- 练习。cpp/Exercises.h - 包含练习的静态函数。
- ComplexNumber.cpp/ComplexNumber.h - 表示复数 object 与教程一致。
Main 相当简单:一组对 Exercises::ExerciseName() 的调用。
Exercises.cpp:
#include "Exercises.h"
void Exercises::ComplexNumberClass() {
ComplexNumber c; /** Runs the blank constructor */
ComplexNumber c1(2, 3); /** Runs the args-filled constructor */
ComplexNumber c2 = c1; /** Runs the copy constructor */
c = c2;
cout << c1 << endl;
}
header 文件只有 header 作为 public static void 函数,即可调用和可执行函数。 ComplexNumber 文件是我认为的问题所在(如果我错了请纠正我):
ComplexNumber.cpp(没有构造函数和访问器):
#include "ComplexNumber.h"
using namespace ComplexNumbers;
using namespace std;
ostream& operator<< (ostream& out, ComplexNumber& num){
out << "(" << num.GetReal() << ", " << num.GetImaginary() << ")";
return out;
}
const ComplexNumber &ComplexNumber::operator=(const ComplexNumber &num) {
cout << "Using assignment operator override" << endl;
real = num.real;
imaginary = num.imaginary;
return *this;
}
ComplexNumber.h:
#ifndef OPERATOROVERLOADING_COMPLEXNUMBER_H
#define OPERATOROVERLOADING_COMPLEXNUMBER_H
#include <iostream>
using namespace std;
namespace ComplexNumbers {
class ComplexNumber {
private:
double real;
double imaginary;
public:
ComplexNumber();
ComplexNumber(double real, double imaginary);
ComplexNumber(const ComplexNumber &num);
const ComplexNumber &operator=(const ComplexNumber &num);
double GetReal() const {
return real;
}
double GetImaginary() const {
return imaginary;
}
};
ostream &operator<<(ostream& out, ComplexNumber& num);
}
#endif //OPERATOROVERLOADING_COMPLEXNUMBER_H
当我构建它时,它告诉我我有一个“对 'cave_of_programming::operator<<(std::ostream&, cave_of_programming::ComplexNumber&)' 的未定义引用。方法 headers 匹配,我正在使用 Jetbrains CLion 构建。
我的研究表明问题出在链接器上,但我查看了我的 CMakeLists.txt 并发现它正在链接所有相应的文件。
SOURCE_FILES main.cpp Exercises.cpp Exercises.h ComplexNumbers/ComplexNumber.cpp ComplexNumbers/ComplexNumber.h
有人知道为什么这不起作用吗?我错过了什么?
问题是您在 class 中定义了 ostream &operator<<(ostream& out, ComplexNumber& num)
。这对编译器没有多大意义,因为它知道在获取 ostream 对象和某种类型的 class 时覆盖 operator<<
,
但是你实现它的方式,它得到了 ostream、一个 ComplexNumber 和另一个 ComplexNumber 作为 'this' 参考。
为了正确重载二元运算符,您有两个选择:
在class中定义运算符,只给它ostream作为参数
class ComplexNumber
{
...
ostream &operator<<(ostream& out) const;
};
或者在class之外定义运算符,并给它两个参数:
class ComplexNumber
{
...
};
ostream &operator<<(ostream& out, const ComplexNumber& num);
请注意,在第二个实现中,如果要访问任何私有成员,则需要将函数添加为 class 的友元。
另请注意,最好像我在示例中那样在此处使用 const,否则您将无法在 const ComplexNumbers 上使用运算符。