电话号码升位(拷贝构造函数)——C++

题目描述

定义一个电话号码类CTelNumber,包含1个字符指针数据成员 。成员函数包含:构造、析构、打印、拷贝构造、判断电话号码合法性函数。

字符指针是用于动态创建一个字符数组,然后保存外来输入的电话号码

构造函数的功能是为对象设置键盘输入的7位电话号码,

拷贝构造函数的功能是用原来7位号码的对象升位为8位号码对象,也就是说拷贝构造的对象是源对象的升级.电话升位的规则是原2、3、4开头的电话号码前面加8,原5、6、7、8开头的前面加2。

注意:合法的电话号码:1、长度为7位;2、电话号码的字符全部是数字字符;3、第一个字符只能是以下字符:2、3、4、5、6、7、8。与上述情况不符的输入均为非法

输入

测试数据的组数 t

第一个7位号码

第二个7位号码

......

输出

第一个号码升位后的号码

第二个号码升位后的号码

......

代码(未优化)

#include <iostream>
#include <cstring>
using namespace std;

class CTeINumber {
public:
    CTeINumber(char *a) {
        tel = new char[strlen(a) + 1];
        strcpy(tel, a);
    }

    ~CTeINumber() {
        delete[] tel;
    }

    void print() {
        if (isLegal()) {
            cout << tel << endl;
        } else {
            cout << "Illegal phone number" << endl;
        }
    }

    CTeINumber(const CTeINumber &p) {
        tel = new char[9];
        strcpy(tel + 1, p.tel);
        if (p.tel[0] == '2' || p.tel[0] == '3' || p.tel[0] == '4') {
            tel[0] = '8';
        } else {
            tel[0] = '2';
        }
        tel[8] = '\0';
    }

    bool isLegal() const {
        if (strlen(tel) != 8) {
            return false;
        }
        for (int i = 0; i < 8; i++) {
            if (tel[i] < '0' || tel[i] > '9') {
                return false;
            }
        }
        if (tel[1] == '0' || tel[1] == '1' || tel[1] == '9') {
            return false;
        }
        return true;
    }

protected:
    char *tel;
};

int main() {
    int t;
    cin >> t;
    while (t--) {
        char a[10];
        cin >> a;
        CTeINumber p1(a);
        CTeINumber p2 = p1;
        p2.print();//islegal是在拷贝后的,已经加一了
    }
    return 0;
}

对深拷贝的理解和运用

{

如果不重新定义开一个动态空间,并用strcpy,(而不是‘=’ —— 错误的)

那类的两个对象中的指针会指向同一个堆区空间,因此析构函数会析构两回这个同一堆区空间而崩溃

}

  1. 当要拷贝的对象有被动态分配内存时——存在char *指针,要进行深拷贝;
  2. 即在拷贝函数中,重新开一个动态内存(new),然后,通过strcpy来复制被拷贝对象的内容到这个新开的动态内存中;
  3. 最后,再把这个动态内存通过等号赋给当前类对象的动态内存中
//直接对当前对象的指针进行分配内存
CTeINumber(const CTeINumber &p) 
{
    tel = new char[9];
    strcpy(tel + 1, p.tel);
    if (p.tel[0] == '2' || p.tel[0] == '3' || p.tel[0] == '4')
    {
        tel[0] = '8';
    } 
    else 
    {
        tel[0] = '2';
    }
    tel[8] = '\0';
}


//在当前进行定义一个新的指针来分配内存,再进行等号=(赋值,指向地址)
CTeINumber(const CTeINumber &p) 
{
    char* tel1 = new char[9];
    strcpy(tel1 + 1, p.tel);
    tel = tel1;
    if (p.tel[0] == '2' || p.tel[0] == '3' || p.tel[0] == '4')
    {
        tel[0] = '8';
    } 
    else 
    {
        tel[0] = '2';
    }
    tel[8] = '\0';
}



对拷贝函数的参数加个&的原因:

引用,就不用在调用参数时再次进行类的拷贝了(在作为函数的参数时,会被拷贝,但引用就不需要了)

对于深拷贝char * 和string的区别

string是可以直接用=,因为string已经做好了其他方面的准备,不会出现上面对于指针的问题

#include <iostream>
using namespace std;

class p {
    string *a; // 指向动态分配的字符串数组
public:
    p(string *a1) : a(new string[10]) { // 构造函数
        for (int i = 0; i < 10; ++i) {
            a[i] = a1[i];
        }
    }

    p(const p &p1) : a(new string[10]) { // 拷贝构造函数
        for (int i = 0; i < 10; ++i) {
            a[i] = p1.a[i];
        }
    }

    ~p() { // 析构函数
        delete[] a;
    }
};

int main() {
    string b = "sdfqc";
    string *a = new string[10]; // 动态分配一个字符串数组
    for (int i = 0; i < 10; ++i) {
        a[i] = b;
    }

    p q(a); // 使用a初始化对象q
    p q1(q); // 使用拷贝构造函数初始化q1

    delete[] a; // 释放动态分配的内存
    return 0;
}

注:当char*赋值给string时,一定要判空(否则会造成程序崩溃):

//会报错代码
#include<iostream>
using namespace std;

int main()
{
    char *p = NULL;
    std::string strP = p; // string不接受NULL赋值
    delete[] p;
}

//预先判空代码
#include<iostream>
using namespace std;

int main()
{
    char *p = NULL;
    if (p == NULL)
    {
        return;
    }
    std::string strP = p;
}

//当然,对于第一个有一些编译器会显示成功,但最好写第二个代码

### C++ 中实现电话号码升位操作 #### 定义 `CTelNumber` 类 为了满足需求,定义了一个名为 `CTelNumber` 的类来表示电话号码。该类包含一个指向字符数组的指针作为私有成员变量,并实现了必要的构造函数、析构函数、打印函数和拷贝构造函数。 ```cpp class CTelNumber { private: char* number; public: // 构造函数 CTelNumber(const char* num); // 拷贝构造函数 CTelNumber(const CTelNumber& q); // 析构函数 ~CTelNumber(); // 打印函数 void Print() const; }; ``` #### 实现构造函数 构造函数用于初始化新创建的对象实例。它接收一个字符串参数并分配足够的内存空间存储这个字符串副本。 ```cpp CTelNumber::CTelNumber(const char* num) : number(nullptr) { if (num != nullptr && strlen(num) == 7 && isdigit(num[0]) && (num[0] >= '2' || num[0] <= '8')) { // 验证合法性[^3] size_t length = strlen(num); number = new char[length + 1]; strcpy(number, num); } } ``` #### 实现拷贝构造函数 当通过已存在的对象去创建另一个对象时会调用此函数。这里需要注意深浅复制的区别——为了避免两个不同对象共享同一块动态分配的数据区域而导致潜在的风险,在此处进行了深层复制处理。 ```cpp CTelNumber::CTelNumber(const CTelNumber& q) : number(nullptr) { if (q.number != nullptr) { size_t length = strlen(q.number); number = new char[length + 1]; // 动态申请新的内存空间 strcpy(number, q.number); // 将原对象的内容复制到当前对象中 } } ``` #### 实现析构函数 每当销毁某个对象的时候都会自动执行其对应的析构函数。在这里释放之前由构造函数或拷贝构造函数所开辟出来的那片堆上资源即可防止内存泄漏的发生。 ```cpp CTelNumber::~CTelNumber() { delete[] number; // 清理掉先前分配给number的空间 } ``` #### 实现打印功能 提供了一种简单的方式让用户可以查看内部保存下来的电话号码信息。 ```cpp void CTelNumber::Print() const { if (number != nullptr) cout << "Phone Number: " << number << endl; else cout << "Invalid phone number." << endl; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值