一个模拟Point点的类,内置函数类型为int.
实现默认构造,自定义构造,拷贝构造、移动构造,拷贝赋值、移动赋值
重载成员运算符函数 “operator+=”、“operator+”、“operator<<”
重载非成员运算法函数 “operator*”
1、类的声明
class TestOperatorPoint {
public:
// default
TestOperatorPoint() = default;
TestOperatorPoint(int x, int y) :
x(x), y(y) //参数名、成员变量可以同名
{}
// copy constructor
TestOperatorPoint(const TestOperatorPoint& pt);
// move constructor
TestOperatorPoint(TestOperatorPoint&& pt);
//// 错误的拷贝赋值
//TestOperatorPoint operator=(const TestOperatorPoint& pt);
// copy assign
TestOperatorPoint& operator=(const TestOperatorPoint& pt);
// move assign
TestOperatorPoint& operator=(TestOperatorPoint&& pt);
////////////////// operations
TestOperatorPoint operator+(const TestOperatorPoint& pt)
TestOperatorPoint& operator+=(const TestOperatorPoint& pt);
// 输出重载(友元函数)
friend std::ostream& operator<< (std::ostream& out, const TestOperatorPoint& pt);
//private:
int x, y;
};
2、类的具体实现
2.1 构造函数和赋值函数
以下类定义时的实现,类定义外实现是需要加类作用域。
// copy constructor
TestOperatorPoint(const TestOperatorPoint& pt)
{
std::cout << "copy constructor" << std::endl;
x = pt.x;
y = pt.y;
}
// move constructor
TestOperatorPoint(TestOperatorPoint&& pt)
{
std::cout << "move constructor" << std::endl;
x = std::move(pt.x); // x,y是基本类型,移动时不影响
y = std::move(pt.y);
}
//// 错误的拷贝赋值
//TestOperatorPoint operator=(const TestOperatorPoint& pt)
//{
// std::cout << "wrong copy assign" << std::endl;
// // x = pt.x;
// //y = pt.y;
// // return *this; // 如果不返回引用,会将*this对象进行一次拷贝赋值,
// return pt; // 直接返回也会再进行一次拷贝赋值,
//}
// copy assign
TestOperatorPoint& operator=(const TestOperatorPoint& pt)
{
std::cout << "copy assign" << std::endl;
x = pt.x;
y = pt.y;
return *this;
}
// move assign
TestOperatorPoint& operator=(TestOperatorPoint&& pt)
{
std::cout << "move assign" << std::endl;
x = std::move(pt.x); // x,y是基本类型,移动时不影响;
y = std::move(pt.y);
return *this;
}
需要说明的是,当成员变量是非基本类型,如string、vector、指针对象以及其他类对象时,move的作用在于减少过多的构造、赋值操作。
例如,如下操作
string str1 = "abc";
string str2 = std::move(str1)
结果是 str1为"",str2为"abc"。 str2进行的是移动构造。
测试代码
TestOperatorPoint pt1;
TestOperatorPoint pt2(3, 4); //自定义构造
TestOperatorPoint pt3(pt2); // 拷贝构造
pt1 = pt2; // 拷贝赋值, pt1已经存在
TestOperatorPoint pt4;
TestOperatorPoint pt5(1, 1);
TestOperatorPoint pt6(2, 2);
TestOperatorPoint pt7(std::move(pt5)); // 移动构造
pt4 = std::move(pt6); // 拷贝赋值, pt4已经存在
2.2 类成员操作符重载(包括友元函数)
- 赋值(=)、下标([ ])、调用( ( ) )和成员访问箭头( -> )必须是成员函数;
- 改变对象状态、递增递减、解引用等与自身类型密切相关的运算符,通常是成员函数;
////////////////// operations
TestOperatorPoint operator+(const TestOperatorPoint& pt)
{
TestOperatorPoint tmp;
tmp.x = x + pt.x;
tmp.y = y + pt.y;
return tmp; // 返回局部临时变量,编译器优化为 移动操作,不要画蛇添足
}
TestOperatorPoint& operator+=(const TestOperatorPoint& pt)
{
x += pt.x;
y += pt.y;
return *this; // 明确是对自己要修改,要返回引用。否则多一次拷贝构造。
}
操作符重载的测试代码,如下
TestOperatorPoint pt1(1, 2);
TestOperatorPoint pt2(3, 4);
// 移动构造(先执行pt1的操作符重载成员函数,返回临时变量进行移动构造)
TestOperatorPoint pt3 = pt1 + pt2;
TestOperatorPoint pt4(0,0);
pt4 += pt1; // 仅调用pt4的+=函数
2.3 普通的非成员操作符重载
- 算术、相等、关系和位运算,以及可以转换任意一端的运算符对象,应该定义为普通的普通的非成员操作符重载。
- 输入输出运算符必须是普通的非成员函数。
2.3.1 operator*(const TestOperatorPoint& pt, T v)和operator*(T v,const TestOperatorPoint& pt)
例如,一个TestOperatorPoint对象,仅想将其成员变量x,y同时扩大一个倍数(可以是int, float, double等非类内置类型int),这种情况可以定义为
// 混合类型表达式定义为普通的非成员函数(第二个参数不是同一个类类型)
template<typename T>
TestOperatorPoint operator*(const TestOperatorPoint& pt, T v)
{
TestOperatorPoint tmp;
tmp.x = pt.x * v; // 会强转为TestOperatorPoint.x的成员类型
tmp.y = pt.y * v;
return tmp;
}
测试使用 TestOperatorPoint pt5 = pt4 * 3.14;,是没有问题;
但是如果我们先交换乘法顺序(对称性),如TestOperatorPoint pt6 = 3.14 * pt4; 这里是无法执行的,因为 3.14 是double类型,是没有定义重载operator*(TestOperatorPoint)函数的,因此我们需要定义如下普通操作符函数
// 上面乘法运算的重载,对称性
template<typename T>
TestOperatorPoint operator*(T v, const TestOperatorPoint& pt)
{
TestOperatorPoint tmp;
tmp.x = pt.x * v; // 会强转为TestOperatorPoint.x的成员类型
tmp.y = pt.y * v;
return tmp;
}
此时,TestOperatorPoint pt6 = 3.14 * pt4;能够正常执行。
2.3.2 重载输入操作符函数 operator<<
通常自定义打印输出的<<函数时,需要访问类的非公有数据成员,因此定义为友元函数。若不需要,可以定义为非友元函数。
自定义打印输入重载运算符。
// 输出重载(定义时实现)
friend std::ostream& operator<< (std::ostream& out, const TestOperatorPoint& pt);
{
out << "[" << pt.x << ", " << pt.y << "]";
return out;
}
当在外部实现友元函数时,函数不要加类的作用域。
std::ostream& operator<< (std::ostream& out, const TestOperatorPoint& pt)
{
out << "[" << pt.x << ", " << pt.y << "]";
return out;
}
例如测试,std::cout << pt4 << std::endl;
本文详细介绍了C++中自定义Point类的运算符重载实现,包括构造函数、赋值运算符、算术运算符及输入输出运算符的重载。通过具体代码示例,展示了如何正确实现拷贝构造、移动构造、拷贝赋值和移动赋值,以及成员运算符和非成员运算符的重载。
9480

被折叠的 条评论
为什么被折叠?



