运算符重载——重载赋值运算符=用于字符串赋值

本文介绍了一个简单的字符串类实现,并详细展示了如何通过重载赋值运算符来实现字符串对象之间的赋值操作。文章包含了一个完整的C++代码示例,用于演示如何创建字符串类、定义必要的构造和析构函数、实现赋值运算符重载,并最终测试这些功能。

题目:

运算符重载——重载赋值运算符=用于字符串赋值

Time/Memory Limit:1000 MS/32768 K
Submitted: 72 Accepted: 44

Problem Description

定义一个字符串类,该类包括一个字符型指针数据成员,构造函数、析构函数、显示字符串函数,以及重载=运算符函数(用于字符串赋值)。在主函数中对字符串对象的赋值运算进行测试。

Input

输入数据有多行,每行包括一个字符串。

Output

输出有多行,对应每个输入数据要求输出两行,第一行是该输入的字符串对象,第二行是定义另一个对象进行赋值运算,将第一个对象赋值给第二个对象。

Sample Input

Hello!
530 i think you!

Sample Output

Hello!
Hello!
530 i think you!
530 i think you!

 

参考代码:

#include <iostream>
#include <string>
using namespace std;
class STRING{
private:
 char *ch;
public:
 STRING(char *c="NULL");
 STRING(STRING &);
 ~STRING();
 STRING& operator=(const STRING &);
 void show();
};
STRING::STRING(char *c){
 ch=new char[strlen(c)+1];
 strcpy(ch,c);
}
STRING::STRING(STRING &c){
 ch=new char[strlen(c.ch)+1];
 strcpy(ch,c.ch);
}
STRING::~STRING(){
 delete []ch;
}
STRING& STRING::operator=(const STRING &c){
 if(this==&c)
  return *this;
 delete []ch;
 ch=new char[strlen(c.ch)+1];
 strcpy(ch,c.ch);
 return *this;
}
void STRING::show(){
 cout<<ch<<endl;
}
int main()
{
 char c[21];
 while(gets(c))
 {
  STRING x(c),y;
  x.show();
  y=x;
  y.show();
 }
 return 0;
}

### C++ 中赋值运算符重载的实现与使用 #### 1. 赋值运算符重载的意义 在 C++ 中,默认情况下,编译器会为每一个类提供一个默认的赋值运算符。这个默认的赋值运算符通过逐成员复制(member-wise copy)完成对象之间的赋值操作。然而,在某些情况下,这种简单的逐成员复制并不能满足需求,例如当类中包含动态分配内存时,或者需要执行特定的资源管理逻辑时,就需要手动重载赋值运算符以确保正确性和安全性[^4]。 #### 2. 赋值运算符重载的基本形式 赋值运算符重载通常定义为类的成员函数,并具有以下特点: - 它是一个成员函数; - 参数建议为 `const` 类型的引用,避免不必要的拷贝; - 返回值类型应为当前类类型的引用 (`T&`),以便支持链式赋值操作[^4]。 下面展示了一个典型的赋值运算符重载实现: ```cpp #include <iostream> #include <cstring> class String { public: // 构造函数 String(const char* str = nullptr) { if (str) { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); } else { m_data = new char[1]; m_data[0] = '\0'; } } // 拷贝构造函数 String(const String& other) { m_data = new char[strlen(other.m_data) + 1]; strcpy(m_data, other.m_data); } // 赋值运算符重载 String& operator=(const String& other) { if (this != &other) { // 自我赋值检查 delete[] m_data; // 释放原有资源 m_data = new char[strlen(other.m_data) + 1]; strcpy(m_data, other.m_data); } return *this; // 支持链式赋值 } // 析构函数 ~String() { delete[] m_data; } // 输出字符串内容 void print() const { std::cout << m_data << std::endl; } private: char* m_data; }; int main() { String s1("Hello"); String s2("World"); s2 = s1; // 调用赋值运算符 s2.print(); // 输出 "Hello" String s3; s3 = s1 = s2; // 链式赋值 s3.print(); // 输出 "Hello" return 0; } ``` 在这个例子中,`String` 类封装了一块动态分配的字符数组。为了防止浅拷贝带来的问题(如双倍删除),必须显式地重载赋值运算符。具体来说,赋值运算符实现了深拷贝逻辑:先释放原有的内存资源,再重新分配一块新的内存并将源对象的内容复制过去。 #### 3. 关键点解析 ##### (1)自我赋值检查 在上面的例子中可以看到这样的判断条件: ```cpp if (this != &other) { ... } ``` 这是为了避免自我赋值引发的问题。如果目标对象和源对象相同,则无需执行任何操作。否则可能会导致未定义行为,例如重复释放同一块内存区域。 ##### (2)返回引用 赋值运算符应该返回对当前对象的引用 (`return *this;`),这使得多个赋值表达式可以连在一起形成所谓的“链式赋值”。例如: ```cpp s3 = s1 = s2; ``` ##### (3)析构旧数据 在处理动态分配的数据结构时,务必记得销毁现有的资源后再进行新资源的初始化工作。这样能够有效预防内存泄漏或悬空指针等问题的发生。 #### 4. 默认赋值运算符的行为 如果没有特别指定,C++ 编译器会自动生成一个默认版本的赋值运算符。它的作用是对所有非静态成员逐一调用它们各自的赋值操作。对于基本数据类型而言,这只是简单地把右侧数值赋予左侧;而对于复合类型(即子对象),则递归触发其内部的赋值过程[^3]。 但是需要注意的是,这种方式仅适用于那些不需要特殊对待的情形——尤其是涉及到动态存储管理的时候往往不够安全可靠,因此有必要自行定制化解决方案。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值