拷贝赋值实现

#include <iostream>
#include <cstring>

using namespace std;

//字符串赋值
char * mcopy(char *desc, const char *source)
{
    if (desc != NULL)
    {
        while (*source)
        {
            *desc++ = *source++;
        }
        *desc = '\0';
        return desc;
    }
    return NULL;
}

template<class T>
class A
{
private:
    T pt;
public:
    A(T t) :pt(t){}
    virtual ~A(){ }
    T getData() const{ return pt; }
    A& operator =(const A &ra);

};

//模板特化
template<>
class A<char *>
{
private:
    char* pt;
public:
    A(char* t) :pt(t){}
    virtual ~A(){ if (pt) delete []pt; }

    char* getData() const{ return pt; }
    A& operator =(const A &ra);

};

template<class T>
A<T>& A<T>::operator = (const A<T> &ra)
{
    T *npt = new T(ra.pt);
    pt = *npt;
    delete npt;
    return *this;
}

//特化 方法2实现
A<char *>& A<char *>::operator = (const A<char *> &ra)
{   
    pt = new char[strlen(ra.pt) + 1];
    mcopy(pt, ra.pt);

    return *this;
}

int main()
{
    A<int> ia(10);
    A<int> ib(12);
    ib = ia;
    cout << ib.getData() << endl;


    /*char a[] = "abc";
    char b[] = "de";*/
    char *a = "acb";
    char * b = "ddcd";

    A<char *> pA(a);
    A<char *> pB(b);
    pB = pA;
    cout << pB.getData() << endl;


    return 0;
}

### C++ 拷贝赋值运算符函数的实现与用法 #### 什么是拷贝赋值运算符? 拷贝赋值运算符是一种特殊的成员函数,用于处理对象之间的赋值操作。它允许开发者自定义当一个对象被赋予另一个同类型的对象时的行为。通常情况下,编译器会提供默认的拷贝赋值运算符,但如果类中有动态分配内存或其他需要特殊处理的情况,则可能需要手动定义该运算符。 形式化地表示,拷贝赋值运算符是一个重载的操作符 `=` 函数,其签名如下: ```cpp class MyClass { public: MyClass& operator=(const MyClass&); }; ``` 其中,`MyClass&` 表示返回当前对象的引用,而 `const MyClass&` 是右操作数的常量引用[^2]。 --- #### 默认行为 如果没有显式定义拷贝赋值运算符,编译器会生成一个默认版本。这个默认版本执行的是逐成员复制(member-wise copy),即将源对象中的每个非静态数据成员逐一复制到目标对象中。然而,在某些场景下,默认行为可能导致问题,例如涉及指针或动态资源管理时可能会引发浅拷贝问题[^1]。 --- #### 手动实现拷贝赋值运算符 为了防止潜在的风险并确保正确性,可以手动实现拷贝赋值运算符。以下是其实现的关键点: 1. **检查自赋值** 需要先判断左操作数和右操作数是否相同,如果相同则无需任何操作以避免不必要的开销甚至错误。 2. **释放现有资源** 如果当前对象已经持有某种资源(如动态分配的内存),应先安全地释放这些资源,然后再进行新资源的分配。 3. **复制新资源** 将右侧对象的数据完全复制过来,包括深拷贝必要的部分。 下面给出一个完整的例子来说明如何实现拷贝赋值运算符: ```cpp #include <iostream> using namespace std; class MyClass { private: int* data; public: // 构造函数 explicit MyClass(int value = 0) : data(new int(value)) {} // 拷贝构造函数 MyClass(const MyClass& other) : data(new int(*other.data)) {} // 拷贝赋值运算符 MyClass& operator=(const MyClass& other) { if (this != &other) { // 自赋值检测 delete data; // 释放原有资源 data = new int(*(other.data)); // 复制新的资源 } return *this; // 返回当前对象的引用 } ~MyClass() { delete data; // 销毁时清理资源 } void display() const { cout << "Value: " << *data << endl; } }; int main() { MyClass obj1(42); MyClass obj2; obj2 = obj1; // 调用了拷贝赋值运算符 obj1.display(); // 输出 Value: 42 obj2.display(); // 输出 Value: 42 return 0; } ``` 在这个例子中,我们展示了如何通过拷贝赋值运算符完成两个对象之间深层次的内容传递,并且避免了常见的陷阱——如重复释放同一块内存等问题。 --- #### 特殊情况:禁用拷贝赋值运算符 有时出于设计考虑,希望阻止某个类的对象被赋值给其他对象。可以通过将拷贝赋值运算符声明为删除状态 (`=delete`) 来达到此目的。例如: ```cpp class NonCopyable { public: NonCopyable() {} NonCopyable(const NonCopyable&) = delete; // 删除拷贝构造函数 NonCopyable& operator=(const NonCopyable&) = delete; // 删除拷贝赋值运算符 }; ``` 这样做的典型应用场景是在单例模式或者线程池等不允许随意复制实例的情况下[^3]。 --- #### 总结 - 拷贝赋值运算符的主要作用在于控制对象间的赋值过程,尤其是在存在动态资源管理需求的时候显得尤为重要。 - 编写时需特别关注三个要点:自赋值检查、旧资源释放以及新资源创建。 - 当不需要支持赋值功能时,可通过`=delete`语法将其禁用掉。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值