输出运算符重载,实际上是 <<
的重载。 <<
实际上是位移运算符,但是在c++里面,可以使用它来配合cout
在控制台打印输出。 cout
其实是ostream
的一个实例,而ostrem
是 类basic_ostream
的一个别名, basic_ostream
里面对 <<
运算符进行了重载,能使用cout <<
来输出内容
#include
using namespace std;
class stu {
public :
string name;
int age;
stu(string name , int age):name(name) , age(age){}
};
int main() {
stu s("王腾" , 16);
cout << s.name << " : " << s.age <<endl;
cout << 18; // operator<<(int n);
cout << "王腾"; // operator<<(char n);
return 0;
}
cout
是 basic_ostream
类的一个对象,它的后面跟上一个 <<
符号,实际上就是调用了 basic_ostream
这个类里面的一个函数 , 函数是: operator<<()
using ostream = basic_ostream<char, char_traits<char>>;
class basic_ostream;
cout << s
; 也就是 operator<<(stu s);
,直接输出对象,那么需要重载 << 符号,因为标准库里面没有 stu
类,同时不建议去修改cout
对应的类的源码,所以应该使用全局的方式定义
#include
using namespace std;
class stu {
public :
string name;
int age;
stu(string name , int age):name(name) , age(age){}
};
ostream& operator<<(ostream & os, stu & s){
os << s.name << " " <<s.age <<endl;
return os;
}
int main() {
stu s0("王腾" , 16);
stu s1("华云飞" , 17);
cout << s0 << s1 ;
return 0;
}
全局的定义方式重载 << :
void operator<<(ostream & os, stu & s)
第一个参数是 cout
对象,第二个参数是要打印的对象,返回值 void
,如果要链式调用,返回值是 cout
对象
第一个参数必须要加上 &
变成引用的类型,因为cout对象的类禁止拷贝
第二个参数加不加都可以,加上的话不会开辟新的空间。
返回值一定得是引用类型,因为cout对象禁止拷贝
输入运算符重载,实际上就是 >>
的重载,用法和上面的输出运算符重载相似
#include
using namespace std;
class stu {
public :
string name;
int age;
stu(){};
stu(string name , int age):name(name) , age(age){}
};
ostream& operator<<(ostream & os, stu & s){
os << s.name << " " <<s.age <<endl;
return os;
}
istream& operator>> (istream& in, stu &s1) {
in >> s1.name >> s1.age;
return in;
}
int main() {
stu s1;
cout << "请输入学生的姓名和年龄:" << endl;
cin >> s1;
//打印学生, 实际上是打印他的名字。
cout << s1 <<endl ;
return 0;
return 0;
}
运行过程:
请输入学生的姓名和年龄:
王腾
12
王腾 12
#include
using namespace std;
class stu {
public :
string name;
int age;
stu(){}
stu(string name , int age):name(name) , age(age){}
};
int main() {
int a = 30;
int b = 40;
a = b; // 把b拷贝放到区域a里面去
//------------------------------------------------
stu s1 ("李宝" , 17);
stu s2 ("王威" , 19);
s2 = s1; //执行 拷贝赋值运算符 函数
stu s3 = s1; // 执行拷贝构造函数
cout << "s1::" << s1.name << "=" <<s1.age <<endl;
cout << "s2::" << s2.name << "=" <<s2.age <<endl;
return 0;
}
拷贝赋值函数 (Copy Assignment Operator Function)是C++中的特殊成员函数,用于定义对象从另一个对象进行拷贝赋值操作时的行为。它使用赋值运算符 = 进行重载,允许对象之间的数据成员进行复制。拷贝赋值函数的声明形式为 ClassName& operator=(const ClassName& other)
,其中 ClassName
是类名
#include
using namespace std;
class stu {
public :
string name;
stu(string name):name(name) {}
//类当中的特殊的成员函数之一: 拷贝赋值函数
stu& operator=(const stu & s2){
cout << "执行 拷贝赋值运算符函数...." <<endl;
name = s2.name;
return *this;
}
};
int main() {
int a = 30;
int b = 40;
int c = 50;
a = b = c;
cout << "a: " << a <<endl;
cout << "b: " << b <<endl;
cout << "c: " << c <<endl;
stu s1("李宝");
stu s2 ("王威");
s1 = s2 ;
cout << "s1::" <<s1.name <<endl;
cout << "s2::" << s2.name <<endl;
return 0;
}
运行结果:
a: 50
b: 50
c: 50
执行 拷贝赋值运算符函数....
s1::王威
s2::王威
#include
class MyClass {
public:
int* data = nullptr;
MyClass(int value):data(new int(value)) {}
// 拷贝赋值函数
MyClass& operator=(const MyClass& other) {
if (this != &other) { // 避免自我赋值 &other->other对象的地址
delete data; // 释放原有资源
data = new int(*other.data); // 执行深拷贝
}
return *this;
}
~MyClass() {
if (data !=nullptr ){
delete data;
data = nullptr;
}
}
};
int main() {
MyClass obj1(36);
MyClass obj2(29);
obj2 = obj1; // 调用拷贝赋值函数
std::cout << *obj2.data << std::endl;
return 0;
}
MyClass 类包含一个指针成员 data。为了避免默认的浅拷贝,自定义了拷贝赋值函数,执行了深拷贝操作。当进行赋值操作 obj2 = obj1 时,拷贝赋值函数被调用,obj2 的 data 成员被复制为 obj1 的 data 成员的副本。这样,每个对象都有独立的资源,避免了指针成员的共享。
2. 资源管理类:在某些情况下,需要确保每个对象拥有独立的资源,而不是共享同一个资源。通过自定义拷贝赋值函数,可以执行深拷贝,从而避免多个对象共享同一资源。
#include
#include
class String {
public:
char* data;
size_t size;
// 有参构造函数
String(const char* str) {
size = strlen(str);
data = new char[size + 1];
strcpy(data, str);
}
// 拷贝构造函数
String(const String& other) {
size = other.size;
data = new char[size + 1];
strcpy(data, other.data);
}
// 拷贝赋值函数
String& operator=(const String& other) {
if (this != &other) { // 避免自我赋值
delete[] data; // 释放原有资源
size = other.size;
data = new char[size + 1];
strcpy(data, other.data);
}
return *this;
}
~String() {
delete[] data;
}
};
int main() {
String str1("Hello");
String str2("World");
str2 = str1; // 调用拷贝赋值函数
std::cout << str2.data << std::endl; // 输出:Hello
return 0;
}
String 类封装了一个动态分配的字符数组作为字符串的存储。自定义了拷贝赋值函数,执行了深拷贝操作,确保每个对象都有独立的字符串资源。当进行赋值操作 str2 =str1
时,拷贝赋值函数被调用,str2 的 data 成员被复制为 str1 的 data 成员的副本。
3. 链式赋值:拷贝赋值函数的返回类型通常是类的引用,这使得可以实现链式赋值,即连续多次赋值操作。
#include
class Counter {
public:
int count;
Counter(int value) : count(value) {}
// 拷贝赋值函数
Counter& operator=(const Counter& other) {
if (this != &other) { // 避免自我赋值
count = other.count;
}
return *this;
}
~Counter(){}
};
int main() {
Counter c1(5);
Counter c2(10);
Counter c3(15);
c3 = c2 = c1; // 链式赋值
std::cout << c1.count << std::endl; // 输出:5
std::cout << c2.count << std::endl; // 输出:5
std::cout << c3.count << std::endl; // 输出:5
return 0;
}
移动赋值函数(Move Assignment Operator Function)是一种特殊的成员函数,用于实现对象的移动赋值操作。它通常以右值引用作为参数,并返回一个对当前对象的引用。移动赋值函数的主要目的是通过直接转移资源拥有权来提高效率,而不是进行深拷贝。
移动赋值函数的声明形式为 ClassName& operator=(ClassName&& other)
,其中 ClassName
是类名。
#include
class String{
public:
char* data;
int size;
String(const char* str) {
size = strlen(str);
data = new char[size + 1];
strcpy(data, str);
std::cout << "有参构造 ..." << std::endl;
}
// 移动赋值函数
String& operator=(String&& other) {
if (this != &other) { // 避免自我赋值
delete[] data; // 释放原有资源
data = other.data; // 转移资源所有权
size = other.size;
other.data = nullptr; // 将移动源对象的资源置为空指针
other.size = 0;
std::cout << "移动赋值 ..." << std::endl;
}
return *this;
}
~String() {
delete[] data;
}
};
int main() {
String str1("Hello");
String str2("World");
str2 = std::move(str1); // 调用移动赋值函数
return 0;
}
String 类表示一个字符串类,拥有字符指针成员 data 和大小成员 size。我们实现了移动赋值函数,通过转移资源所有权来实现高效的移动操作。在 main() 函数中,使用 std::move()
将 str1 转换为右值,然后将其赋值给 str2。这将调用移动赋值函数,并将 str1 的资源转移到 str2,避免了不必要的字符串拷贝。
#include
#include
class LargeData {
public:
std::vector<int> data;
LargeData(std::initializer_list<int> values) : data(values) {
std::cout << "Constructor called" << std::endl;
}
// 移动赋值函数
LargeData& operator=(LargeData&& other) {
if (this != &other) { // 避免自我赋值
data = std::move(other.data); // 转移资源所有权
std::cout << "Move assignment operator called" << std::endl;
}
return *this;
}
};
int main() {
LargeData data1{1, 2, 3, 4, 5};
LargeData data2{6, 7, 8, 9, 10};
data2 = std::move(data1); // 调用移动赋值函数
return 0;
}
LargeData 类表示一个大型数据类,其中使用 std::vector 存储数据。实现了移动赋值函数,通过转移 std::vector 的资源所有权来实现高效的移动操作。在 main() 函数中,使用 std::move() 将 data1 转换为右值,并将其移动赋值给 data2。这将调用移动赋值函数,并将 data1 的资源转移到 data2,避免了不必要的数据拷贝。
class ResourceHolder {
public:
ResourceHolder() { /* 执行资源分配操作 */ }
ResourceHolder(const ResourceHolder&) = delete; // 禁用拷贝构造函数
ResourceHolder& operator=(const ResourceHolder&) = delete; // 禁用拷贝赋值运算符
ResourceHolder(ResourceHolder&& other) noexcept {
// 移动构造函数,将资源从other转移到当前对象
this->resource_ = other.resource_;
other.resource_ = nullptr;
}
ResourceHolder& operator=(ResourceHolder&& other) noexcept {
// 移动赋值运算符,将资源从other转移到当前对象
if (this != &other) {
releaseResource(); // 释放当前对象的资源
this->resource_ = other.resource_;
other.resource_ = nullptr;
}
return *this;
}
private:
Resource* resource_; // 假设有一个指向某个资源的指针
void releaseResource() {
if (resource_) {
/* 执行资源释放操作 */
delete resource_;
resource_ = nullptr;
}
}
};