类的六大函数复习

0.引言

// 1.拷贝构造函数
Str(const Str& x)//形参必须是引用,最好是const 引用
    : val(x.val)//将原有类的val拷贝给新类的val,注意有时候需要深拷贝
  {
    std::cout<<"Copy constructer is called!"<<std::endl;
  }

// 2.移动构造函数 
Str(Str&& x)//偷资源的过程就是一个写操作,不能定义为const
  : val(x.val), a(std::move(x.a))
  {
  }
//移动构造函数使用:
  Str m;
  Str m2 = std::move(m);

// 3.拷贝赋值函数
Str& operator = (const Str& x)
{
	std::cout<< "copy assignment is called!"<<std::endl;
	val = x.val;//完成拷贝操作
	a = x.a;
	return *this;//返回一直一般是*this
}

// 4.移动赋值函数
Str& operator = (const Str&& x)
{
  std::cout<< "move assignment is called!"<<std::endl;
  //首先做一个判断
  if(&x == this)//自己给自己赋值
  {
    std::cout<<"dunmmy assignment"<<std::endl;
    return *this;
  }
  std::cout<<"real assignment"<<lstd::endl;
  delete ptr;
  ptr = x.ptr;
  x.ptr = nullptr;

  val = std::move(x.val);//完成拷贝操作
  a = std::move(x.a);
  return *this;//返回一直一般是*this
}

请添加图片描述

按行看。

1.构造函数

  • 普通构造函数:略。
  • 代理构造函数
#include<iostream>
#include<vector>

class Str{
public:
  Str()//隐式的返回类型,就是类本身
  {
    std::cout<< "constructer is called!"<<std::endl;
  }

  Str(int input){//构造函数重载
    x = input;
    std<<x<<std::endl;
  }
-------------
  //代理构造函数
  Str Str(int input = 3){
    x = input;//具有默认参数
  }

  Str() : Str(3){

  }

  void fun(){
    std::cout<<x<<std::endl;
  }
private:
  int x;
};

int main(){
  Str m;//constructer is called!
  Str n(3);//3
}
#include<iostream>
#include<vector>
class Str{
public:

  //代理构造函数
  Str() : Str(3){
    std::cout<<"here_1<<std::endl;
  }

  Str(int input){
    std::cout<<"here_2"<<std::endl;
    x = input;
  }
  void fun(){
    std::cout<<x<<std::endl;
  }
private:
  int x;
};

int main(){
  Str m(30);
  m.fun()//30
  //here_2 \ here_1 :先执行代理构造函数,再执行原始构造函数
  Str n();
  n.fun();//3 :代理构造函数
}
  • 初始化列表:区分数据成员的初始化与赋值, 通常情况下可以提升系统性能
#include<iostream>
#include<vector>
#include<string>
class Str{
public:
  Str(const std::string& val ) : x(val), y(0)//初始化列表
  {
    std::cout<<"Pre-assignment: "<< x <<std::endl;
    std::cout<<"Post-assignment: "<< x <<std::endl;
  }
private:
  std::string x;
  int y;
};

int main(){
  Str m("abc");
  //Pre-assignment: abc
  //Post-assignment: abc
}
  • 一些情况下必须使用初始化列表(如类中包含引用成员)
#include<iostream>
#include<vector>
#include<string>
class Str{
public:
  //引用必须使用初始化列表进行初始化
  Str(const std::string& val, 
    int& p_i/*这里也必须是引用,不然ref是绑定到形参上的*/ ) 
    : x(val), ref(p_i)
  {
    std::cout<<"Pre-assignment: "<< x <<std::endl;
    std::cout<<"Post-assignment: "<< x <<std::endl;
    ref = 3;//这是赋值,也不是初始化,只能使用初始化列表进行初始化
  }
private:
  std::string x;
  int& ref;
};

int main(){
  int val;
  Str m("abc", val);//合法
  stc::cout<<val<<std::endl;//3
}

2.拷贝构造函数

拷贝构造函数:拷贝构造函数的形参必须得是引用类型。但是形参为Str& x引用类型的话,在新类里面就容易对原有类进行更改,所以此时最好的形参类型应该是 ‘const Str& x’ 禁止修改,只读

Str(const Str& x)
    : val(x.val)//将原有类的val拷贝给新类的val,注意有时候需要深拷贝
  {
    std::cout<<"Copy constructer is called!"<<std::endl;
  }

如果未显式提供拷贝构造函数,那么编译器会自动合成一个,合成的版本会依次对每个数据成员调用拷贝构造。

  Str() = default;//缺省构造函数
  Str(const Str&) = default;//缺省拷贝构造函数:不需要具体形参名

3.移动构造函数

移动构造函数 :接收一个当前类右值引用对象的构造函数,移动构造函数:能进一步提升系统的性能。

Str(Str&& x)//偷资源的过程就是一个写操作,不能定义为const
  : val(x.val), a(std::move(x.a))
  {
  }

Str(Str&& x)=default;//缺省移动构造函数

移动构造函数使用:

  Str m;
  Str m2 = std::move(m);

移动构造函数通常声明为不可抛出异常的函数–noexcept

struct Str2{
  //定义了拷贝构造函数,编译器就不会定义缺省拷贝构造函数,
  //同时也不会定义缺省移动构造函数
  //也不会定义缺省构造函数
  Str2(const Str2&){
    std::cout<<"Str2 copy constructer is called!"<<std::endl;
  }
  //移动构造函数是去偷别人的资源,默认是正确的
  Str2(Str2&&) noexcept //声明为不可抛出异常的函数
  {
    std::cout<<"Str2 move constructer is called!"<<std::endl;
  }

  //人为定义缺省构造函数
  Str2() = default;
};


struct Str{
  Str() = default;//缺省构造函数
  Str(const Str&) = default;//缺省拷贝构造函数:不需要具体形参名
  //此时,缺省移动构造函数对m_str2的行为是什么?
  缺省移动构造函数,声明为不可抛出异常的函数
  Str(Str&& x) noexcept = default;

  int val = 3;
  std::string a= "abc";
  Str2 m_str2;
};


4.拷贝赋值函数( operator = )

#include<iostream>
#include<vector>
#include<string>

struct Str{
  Str() = default;
  Str(const Str&) = default;
  Str(Str&& x) noexcept  = default;

  int val = 3;
  std::string a= "abc";
};

int main(){
    Str m;
    //调用移动构造
    Str m2 = std::move(m);
    //调用拷贝构造
    Str m2 = m;
    //此时是赋值,会调用,拷贝赋值或移动赋值函数
    //不是构造,是赋值了!!,此时还没定义拷贝赋值函数,会报错
    m2 = m;
}

拷贝赋值函数

#include<iostream>
#include<vector>
#include<string>

struct Str{
  Str() = default;
  Str(const Str&) = default;
  Str(Str&& x) noexcept  = default;

  - 拷贝赋值函数:返回类型为当前类引用
  - operator与=之间可加空格可不加
  - 形参的填写,类似于拷贝构造函数
  - 函数名就是 operator = 
  Str& operator = (const Str& x)
  {
    std::cout<< "copy assignment is called!"<<std::endl;
    val = x.val;//完成拷贝操作
    a = x.a;
    return *this;//返回一直一般是*this
  }

  int val = 3;
  std::string a= "abc";
};

int main(){
    Str m;
    Str m2;
    - 此时是赋值,调用拷贝赋值函数
    - copy assignment is called!
    - C++ insights查看内部操作为:
    - m2.operator = (m);
    m2 = m;
    ------
    Str m3;
    //拷贝复制函数返回类型为引用,返回的值为*this,
    //能实现连等的功能,如果返回值不是引用就没办实现
    m3 = m2 = m;
}

5.移动赋值函数 ( operator = )

移动赋值函数

#include<iostream>
#include<vector>
#include<string>

struct Str{
  Str() = default;
  Str(const Str&) = default;
  Str(Str&& x) noexcept  = default;

  //拷贝赋值函数
  Str& operator = (const Str& x)
  {
    std::cout<< "copy assignment is called!"<<std::endl;
    //包含指针
    val = x.val;//完成拷贝操作
    a = x.a;
    return *this;//返回一直一般是*this
  }

  //移动赋值函数
  //this->m; x->m
  Str& operator = (const Str&& x)
  {
    std::cout<< "move assignment is called!"<<std::endl;
    //首先做一个判断
    if(&x == this)//自己给自己赋值
    {
      std::cout<<"dunmmy assignment"<<std::endl;
      return *this;
    }
    std::cout<<"real assignment"<<lstd::endl;
    delete ptr;
    ptr = x.ptr;
    x.ptr = nullptr;

    val = std::move(x.val);//完成拷贝操作
    a = std::move(x.a);
    return *this;//返回一直一般是*this
  }

  int val = 3;
  std::string a= "abc";
  //假设包含一个指针
  int* ptr;
};

int main(){
    Str m;
    Str m2;
    //dunmmy assignment
    m = std::move(m);
    //real assignment
    m = std::move(m2);
}

6.析构函数

7.总结

= default 表示使用缺省**函数, = delete 则是禁用默认**函数。通常来说,一个类:

  • 如果需要定义析构函数,那么也需要定义拷贝构造与拷贝赋值函数
  • 如果需要定义拷贝构造函数,那么也需要定义拷贝赋值函数
  • 如果需要定义拷贝构造(赋值)函数,那么也要考虑定义移动构造(赋值)函数

见引言图。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值