C++big three(构造函数、拷贝构造函数,拷贝赋值函数)

2023-05-16

       一个类中只要带有指针类型的成员,就必须自己写出big three(构造函数、拷贝构造函数,拷贝赋值函数),如果没有指针类型的成员,大部分情况下可以用默认的。

       字符串类是一个经典的例子:

#ifndef __MYSTRING__
#define __MYSTRING__

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

class String
{
public:                                 
   String(const char* cstr=0);  //构造函数,加const表示不修改*cstr的值                   
   String(const String& str);   //拷贝构造函数,加const表示不修改str指向的值,用&只占用4个字节的内存                 
   String& operator=(const String& str);   //拷贝赋值函数,加const表示不修改str指向的值,用&只占用4个字节的内存
   ~String();                                    
   char* get_c_str() const { return m_data; }
private:
   char* m_data;
};

inline
String::String(const char* cstr)
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}

inline
String::~String()
{
   delete[] m_data;  //由于构造函数是new了一个数组,所以析构函数也需要使用delete []
}

//返回值为String&类型,&表示要赋值的目的端已经存在,即s1 = s2; s1已存在
//并且有时候会连续赋值,s1 = s2 = s3; 所以需要返回值为String&类型
inline
String& String::operator=(const String& str)
{
   if (this == &str)  //检测自我赋值,这一步必须有,本行的&str和形参的&str意义不一样。如果s1 = s2;则形参&str == s2,本行&str == &s2
      return *this;

   delete[] m_data;
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}


//输出字符串操作符重载,不能是一个成员函数,否则使用的时候方向要相反,即需要这样用 s1 << cout
ostream& operator<<(ostream& os, const String& str)
{
   os << str.get_c_str();
   return os;
}

#endif

1.构造函数、析构函数和拷贝构造函数

inline
String::String(const char* cstr)  //构造函数
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}
inline
String::~String()  /析构函数
{
   delete[] m_data;  //由于构造函数是new了一个数组,所以析构函数也需要使用delete []
}
inline
String::String(const String& str)  //拷贝构造函数
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}

       根据代码规范,不超过10行的函数可以定义为内联函数,所以在构造和析构函数前都加了inline,上面构造函数超过了10行,但是内联不内联是由编译器决定的,所以加上inline也没啥毛病。
       构造函数中,如果传入的参数有效的话则new一个strlen(cstr)+1大小的数组给成员变量,并将参数拷贝到成员变量中;
       如果传入的参数无效,则将’\0’传给成员变量,当然,也需要new一个字节的空间来保存。
       构造函数的使用:

  String s1();  //参数无效 
  String s2("world");  //参数有效

       对于析构函数,由于构造函数是new了一个数组,所以析构函数也需要使用delete []。

       拷贝构造函数的参数类型就是类的类型,初始化步骤如代码所示。
       拷贝构造函数的使用:

String s2("world");
String s3(s2);

2.拷贝赋值函数

//返回值为String&类型,&表示要赋值的目的端已经存在,即s1 = s2; s1已存在
//并且有时候会连续赋值,s1 = s2 = s3; 所以需要返回值为String&类型
inline
String& String::operator=(const String& str)
{
   if (this == &str)  //检测自我赋值,这一步必须有,本行的&str和形参的&str意义不一样。如果s1 = s2;则形参&str == s2,本行&str == &s2
      return *this;

   delete[] m_data;
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}

       ①拷贝赋值函数的返回值类型应是by reference(传引用),因为拷贝赋值函数是将一个对象赋值给另一个对象,即要复制的目的端已经存在,所以可以用引用;还有一个原因是调用拷贝赋值函数是有可能是连续赋值的,如s1 = s2 = s3; ,这也需要返回值类型为引用才可以。
       ②拷贝赋值函数必须要有检测自我赋值这一步,检测自我赋值一个好处是当是自我赋值时后面的几步不需要再执行,从而节省了时间。另一个必要原因就是如果没有检测自我赋值这一步,并且遇到自我赋值时,代码逻辑会出错。
构造函数在赋值前会delete自己的成员变量,如果是自我赋值的话,会清空当前对象的值,后面赋值时对象已经被delete了,所以对象中保存的内容已经不能确定是什么了。

关于返回值类型必须使用值传递的函数的问题

       如下面的程序:

class complex
{
public:
  complex (double r = 0, double i = 0): re (r), im (i) { }
  double real () const { return re; }   //加const表示不会改变数据内容,尽量加上const
  double imag () const { return im; }
private:
  double re, im;
};

inline double
imag (const complex& x)
{
  return x.imag ();
}

inline double
real (const complex& x)
{
  return x.real ();
}

inline complex
operator + (const complex& x, const complex& y)  //返回值不能用by reference,因为如果是c1 + c2;这一句执行完后c1 + c2的值在函数结束后就被释放了,
                                                 //如果用by reference,会返回错误的东西
{
  return complex (real (x) + real (y), imag (x) + imag (y));
}

       上面的“+”操作符重载函数的返回值就必须使用值传递,因为当函数返回后,函数中的变量就会随着函数返回,其生命周期也就随之结束,如果返回类型使用引用的话,那么引用指向的内存也是不存在的,所以这种函数的返回类型不能使用引用传递。
       注:上面的“+”操作符重载函数应该有三个,此处只写了一个。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++big three(构造函数、拷贝构造函数,拷贝赋值函数) 的相关文章

  • 求大数的阶乘的位数:PKU :1423:Big Number

    题目描述 xff1a Description In many applications very large integers numbers are required Some of these applications are usin
  • 拯救者14OpenCore0.6.4黑苹果Big Sur 2020年12月11日

    型号 xff1a 联想 xff08 Lenovo xff09 拯救者 14 0英寸游戏本 xff08 i7 4720HQ 8G 128G SSD 43 1T GTX960M 原配置如上 后来又加了根内存 xff0c 机械盘换成了ssd 20
  • 拯救者14OpenCore0.6.8黑苹果Big Sur 2021年4月12日

    型号 xff1a 联想 xff08 Lenovo xff09 拯救者 14 0英寸游戏本 xff08 i7 4720HQ 8G 128G SSD 43 1T GTX960M 原配置如上 后来又加了根内存 xff0c 机械盘换成了ssd 特色
  • C++ 构造函数和New运算符

    算法和数据结构就是编程的一个重要部分 xff0c 你若失掉了算法和数据结构 xff0c 你就把一切都失掉了 系统会自动在栈中为每个变量开辟内存空间 xff0c 以保证数值被合理地存放 由于栈是系统自动分配的 xff0c 因此速度较快 xff
  • 拷贝构造函数

    拷贝构造函数是重载构造函数的一种重要形式 xff0c 它的功能是使用一种已经存在的对象去初始一个新创建的同类对象 xff0c 它可以将一个已有对象的数据成员的值拷贝给正在创建的另一个同类的对象 拷贝构造函数与类同名 xff0c 没有返回值
  • UVA1185 Big Number

    原题 https www luogu com cn problem UVA1185 本题用到的定理的证明 https www cnblogs com weiliuyby p 5831991 html 题目 给出n 求n 的位数 从网上找到了
  • Python读取各种格式的txt文档(ANSI、Unicode、Unicode big endian、UTF-8等)

    https blog csdn net Ltinginger article details 83105266
  • three.js加载3D模型(glb/gltf/fbx)

    three js加载3D模型 glb gltf fbx 一 理解three 1 一个可以在某个3D建模软件打开的东西 xff0c 通过某种方案在浏览器中打开 xff1b 2 不要试图手动去创建3D图形 xff0c 当然比较闲的话可以这样操作
  • threejs的dat.gui辅助工具的使用

    threejs的dat gui辅助工具的使用 安装 使用 安装 npm i dat gui S 使用 import dat from dat gui const controlData rotationSpeed 0 01 color 66
  • C++ 拷贝(复制)构造函数详解

    拷贝构造函数 特殊的构造函数 用户未定义拷贝函数的情况下 系统自动创建一个隐式的默认拷贝构造函数 它将已经存在的对象中的数据成员逐个的拷贝到新创建的对象中 自定义拷贝构造函数格式 类名 const 类名 引用名 会调用拷贝函数的三种情况 1
  • c++ oop构造函数与拷贝控制

    class Quote public Quote int x x x 如果我们删除的是一个指向派生类对象的基类指针 则需要虚析构函数 virtual Quote default 动态绑定析构函数 int x virtual void sho
  • 什么时候要有拷贝构造函数?

    1 构造对象 时 用已实例化的对象进行构造 int main Student a 10 2 Student b a 拷贝构造 并且要特别注意指针数据成员的赋值 避免出现野指针的情况 2 返回临时对象 而不是返回对象的引用 rmb opera
  • Java private类构造函数笔记

    前言 最近在看Android源码的时候遇到了private类构造函数 于是写了一个测试小程序 帮助理解 代码 class TestPrivate private TestPrivate System out println TestPriv
  • 自动调用拷贝构造函数的三种情况

    自动调用拷贝构造函数的三种情况 首先介绍拷贝构造函数的定义形式 class 类名 public 构造函数名称 类名 变量名 函数体 拷贝构造函数是使用类对象的引用作为参数的构造函数 它能够将参数的属性值拷贝给新的对象 完成对新对象的初始化
  • 全面理解java中的构造方法以及this关键字的用法(超详细)

    Hello 各位铁汁们 我是小 儿哈 今天我又来更新我的Java基础学习博客了 本篇主要内容概述 1 如何用构造方法初始化对象 2 为啥要有this这个关键字 3 this 属性名访问成员变量 成员方法 4 this 方法名 this 的用
  • 类模板以及赋值运算符重载、拷贝构造函数

    编译器默认的拷贝构造函数 是发生的浅拷贝 像指针的赋值就会让指针指向同一个地址空间 析构时就会对同一个地址空间释放两次 就会造成程序崩溃 自定义在模板内的拷贝构造函数 Queue const Queue
  • 工厂函数和构造函数的区别

    工厂函数和构造函数的区别 下面是给出的两个都是实现 定义使用值的范围 的函数 第一个工厂函数 工厂模式 用以创建并初始化类的实例 而且给出了一个表示 值的范围 的类定义了原型对象 第二个是使用构造函数代替工厂函数来实现相同功能的代码段 下面
  • Java基础十一(private、this关键字和构造函数)

    私有private关键字 成员变量是否一定需要全部向外界访问 如果需要向外界访问 则public 如不需要向外界访问 则private 但是一般而言 都会将成员变量私有化 给成员变量 private是彻底不想给外界类中不需要对外提供的内容都
  • C++:派生类的默认构造函数和拷贝构造函数调用基类构造函数的机制(含程序验证)

    1 如果基类定义了不带参数的默认构造函数 则编译器为派生类自动生成的默认构造函数会调用基类的默认构造函数 2 如果基类定义了拷贝构造函数 则编译器为派生类自动生成的拷贝构造函数同样会调用基类的拷贝构造函数 3 如果基类定义了带参数的构造函数
  • C++编译器为类自动生成的函数

    我们可以构建一个空类 class Empty 尽管没有定义任何函数 但我们可以通过以下方式使用这个类 Empty e1 Empty e2 e1 e2 e1 因为当编译器发现你用上述方式使用这个类而却在类声明中没有定义一般构造函数 非复制构造

随机推荐

  • iptables nat

    NAT一般情况下分为SNAT xff0c DNAT和PNAT 此篇主要讲述的是使用iptables配置NAT xff0c 所以这3种NAT的区别和应用场景就简单的说明一下 SNAT xff1a 源地址转换 目标地址不变 xff0c 重新改写
  • Qt 的Cmake方式如何创建资源文件和添加类

    今天看到有人问Qt 的Cmake方式如何创建资源文件 xff0c 这个问题和添加类都是一样的 xff0c 也有朋友问如何添加类 xff0c 百度的回答是把cmake改成Qmake 这样等于没有回答 xff0c 根据自己的经验我在这里回答一下
  • ajax 请求头Authorization 添加账号密码访问

    在header中添加 34 Authorization 34 字段 xff0c 值为 34 api key api secret 34 进行base64加密后 在前面加入 34 Basic 34 Basic后有空格 字符串 最后形式为 34
  • Authorization—权限控制流程

    本篇是对Shiro体系架构的介绍 xff0c 本栏目大部分内容来自于Shiro官网 翻译过程中已经尽量保证用词的准确性和易懂性 xff0c 如有不准确或者不确切的地方 xff0c 请联系作者加以修改 本篇内容翻译自Authorization
  • C语言在头文件中用extern架起变量沟通的桥梁

    span class hljs comment a c span span class hljs keyword int span foo span class hljs keyword int span bar span class hl
  • 【C语言】5. 指针free后为什么要刻意指向NULL、野指针(原因、解决)、悬垂指针

    目录 1 指针free后为什么还要刻意指向NULL xff1f 2 野指针2 1 什么是野指针 xff1f 2 2 野指针形成的原因2 3 如何避免野指针 3 悬垂指针3 1 什么是悬垂指针 xff1f 3 2 示例代码3 3 解决方法 1
  • 【QT】UDP通信QUdpSocket(单播、广播、组播)

    目录 1 UDP通信概述2 UDP消息传送的三种模式3 QUdpSocket类的接口函数4 UDP单播和广播代码示例4 1 测试说明4 2 MainWindow h4 3 MainWindow cpp4 4 界面展示 5 UDP组播代码示例
  • Fiddler 调试HTTP工具,帮助Debug HTTP连接的免费工具

    Fiddler是一个C 实现的浏览器抓包和调试工具 xff0c fiddler启用后作为一个proxy存在于浏览器和服务器之间 xff0c 从中监测浏览器与服务器之间的http https级别的网络交互 目前可以支持各种主要浏览器如IE C
  • 对话框使用VIEW (转)

    现在的程序功能越来越复杂 xff0c 很多功能要求能在对话框中实现复杂的功能 xff0c 而在对话框中使用视图不像使用一些诸如静态控件 xff0c 编辑控件等那么方便 xff0c 下面文章用实例说明如何在对话框中使用视图 正文 http w
  • ubuntu系统下安装putty

    1 打开终端 xff0c 使用下面的命令来安装putty xff1a 1 1 sudo apt get update 1 2 sudo apt get install putty 上面两步成功则说明putty安装成功 2 接下来配置putt
  • 改变linux shell的输出效果

    文本终端的颜色可以使用 ANSI非常规字符序列 来生成 举例 xff1a echo e 34 033 44 37 5m ME 033 0m COOL 34 以上命令设置背景成为蓝色 xff0c 前景白色 xff0c 闪烁光标 xff0c 输
  • GNU ARM 汇编指令

    原文地址 http blog sina com cn s blog 59b189220100au1k html 第一部分 Linux下ARM汇编语法尽管在Linux下使用C或C 43 43 编写程序很方便 xff0c 但汇编源程序用于系统最
  • 什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决?

    什么是序列化 序列化 xff1a 把对象转换为字节序列的过程称为对象的序列化 反序列化 xff1a 把字节序列恢复为对象的过程称为对象的反序列化 怎么序列化 实现Serializable接口 xff0c 指定serialVersionUID
  • 寻迹小车笔记——红外对管(TCRT5000)原理

    一 概述 深色 xff08 黑色 xff09 的是发射端 xff0c 白色 xff08 透明 xff09 的是接收端 中间蓝色的是可以调节灵敏度的旋钮 TCRT5000光电传感器模块是基于TCRT5000红外光电传感器设计的一款红外反射式光
  • C语言判断一个数是否是水仙花数

    水仙花数是指一个N位正整数 xff08 N 3 xff09 xff0c 它的每个位上的数字的N次幂之和等于它本身 例如 xff1a 153 61 1 3 43 5 3 43 3 3 include lt stdio h gt int nar
  • C语言分类统计字符个数

    题目来源 xff1a 分类统计字符个数 PTA 本题要求实现一个函数 xff0c 统计给定字符串中英文字母 空格或回车 数字字符和其他字符的个数 函数接口定义 xff1a void StringCount char s 其中 char s
  • MIPS单周期CPU的设计——I型指令的设计

    一 一些概念 1 单周期CPU 指令周期 xff1a CPU从内存取出一条指令并执行这条指令的时间总和 CPU周期 xff1a 又称机器周期 xff0c CPU访问一次内存所花的时间较长 xff0c 因此用从内存读取一条指令字的最短时间来定
  • MIPS单周期CPU设计——lw和sw指令的设计

    1 lw xff0c sw指令格式及功能 指令 31 26 25 21 20 16 15 0 意义lw100011rsrtoffset从数存 xff08 数据存储器 xff09 中取数据写进寄存器sw101011rsrtoffset将寄存器
  • 计算机网络传输层概念及其协议

    一 概念 链路层保证的是点到点的可靠传输 xff0c 传输层保证端到端的可靠性 传输层是进程之间的通信 传输实体 xff1a 在收 发两端的传输层实现对等实体通信的硬件或软件 实现TCP协议的用户进程或者硬件称为TCP的传输实体 二 TCP
  • C++big three(构造函数、拷贝构造函数,拷贝赋值函数)

    一个类中只要带有指针类型的成员 xff0c 就必须自己写出big three xff08 构造函数 拷贝构造函数 xff0c 拷贝赋值函数 xff09 xff0c 如果没有指针类型的成员 xff0c 大部分情况下可以用默认的 字符串类是一个