三、运算符重载
1、友元(熟悉)
1.1 概念
类通过私有成员实现数据封装,但某些场景下频繁访问私有成员会导致效率问题。友元机制允许特定函数/类访问私有成员,但会破坏封装性,需谨慎使用。
友元实现方式:
- 友元函数
- 友元类
- 友元成员函数
1.2 友元函数
友元函数是类外定义的普通函数,需在类内用friend
声明。
特点:
- 无
this
指针 - 声明位置不受访问权限限制
- 可访问多个类的私有成员(需在各自类中声明)
示例代码
#include <iostream>
using namespace std;
class Test {
private:
int a;
public:
Test(int i) : a(i) {}
void show() { cout<< a << " " << &a << endl; }
// 友元函数声明
friend void and_test(Test &t);
};
// 友元函数定义
void and_test(Test &t) {
cout << t.a << " " << &t.a << endl;
}
int main() {
Test t1(1);
and_test(t1); // 输出与成员函数相同
t1.show();
return 0;
}
1.3 友元类
若类B是类A的友元类,则B可访问A的所有成员。
特性:
- 友元关系不可继承
- 不具有交换性(需双向声明)
互为友元示例
class Cat; // 前向声明
class Test {
private:
int a;
public:
Test(int i) : a(i) {}
void test(Cat &c);
friend class Cat; // 声明Cat为友元类
};
class Cat {
private:
int b;
public:
Cat(int i) : b(i) {}
void test1(Test &t) {
cout << t.a++ << endl; // 访问Test私有成员
}
friend class Test; // 双向友元
};
void Test::test(Cat &c) {
cout << c.b << endl; // 访问Cat私有成员
}
int main() {
Test t(44);
Cat c(12);
c.test1(t); // 输出45(Test的a自增)
return 0;
}
1.4 友元成员函数
使类B的特定成员函数成为类A的友元,可访问A的私有成员。
实现步骤:
- 前向声明目标类
- 在目标类中声明友元成员函数
- 定义成员函数时需指定类作用域
示例代码
class Test; // 前向声明
class B {
public:
void and_test(Test &t); // 声明友元成员函数
};
class Test {
private:
int a;
public:
Test(int i) : a(i) {}
friend void B::and_test(Test &t); // 声明友元成员函数
};
void B::and_test(Test &t) {
cout << t.a << endl; // 访问Test私有成员
}
int main() {
Test t1(2);
B b;
b.and_test(t1); // 输出2
return 0;
}
2、运算符重载(掌握)
2.1 概念
允许为自定义类型重载运算符,使其支持类似内置类型的操作。
实现方式:
- 友元函数重载
- 成员函数重载
2.2 友元函数运算符重载
适用于需要对称性的操作(如二元运算符)。
示例:+运算符
class MyInt {
private:
int a;
public:
MyInt(int a) : a(a) {}
friend MyInt operator+(MyInt &i, MyInt &i2); // 友元声明
};
MyInt operator+(MyInt &i, MyInt &i2) {
return MyInt(i.a + i2.a); // 隐式调用构造函数
}
示例:++运算符
class MyInt {
// ...
friend MyInt operator++(MyInt &i); // 前置++
friend MyInt operator++(MyInt &i, int); // 后置++
};
MyInt operator++(MyInt &i) { return ++i.a; } // 前置
MyInt operator++(MyInt &i, int) { return i.a++; } // 后置
2.3 成员函数运算符重载
隐含this
作为左操作数,适用于非对称操作。
示例:+运算符
class MyInt {
public:
MyInt operator+(MyInt &i2) {
return MyInt(this->a + i2.a);
}
};
2.4 特殊运算符重载
2.4.1 赋值运算符重载
默认生成浅拷贝,需手动实现深拷贝。
class MyInt {
public:
MyInt& operator=(MyInt &i) {
if (this != &i) this->a = i.a;
return *this;
}
};
2.4.2 类型转换运算符重载
必须为成员函数,返回目标类型。
class MyInt {
public:
operator int() { return a; } // 转int
operator string() { return "hello"; } // 转string
};
2.5 注意事项
- 不可创建新运算符
- 不支持默认参数
- 不改变优先级和结合性
- 建议:双目用友元,单目用成员
3、std::string 字符串类
核心操作示例
string s1 = "hello";
string s2("world");
// 拼接与追加
s1 += s2; // s1 = "helloworld"
s1.append("!!!"); // s1 = "helloworld!!!"
// 插入与删除
s1.insert(5, " "); // s1 = "hello world"
s1.erase(5, 6); // s1 = "hello"
// 替换与清空
s1.replace(0, 5, "Hi"); // s1 = "Hi"
s1.clear();
// C风格转换
char arr[10];
strcpy(arr, s1.c_str()); // C字符串转换