首頁 > 軟體

C++賦值函數+移動賦值函數+移動建構函式詳解

2022-08-30 18:04:02

左值參照和右值參照

左值與右值

左值:在記憶體中佔有確定位置的物件,即左值佔有記憶體。換句話來說,就是有地址,有值。

右值:不佔記憶體(科學地講是臨時暫存器),僅有值,為臨時變數。

左右值的切換

右值->左值:用*符號。

int a=10;
int* b=&a;// b為右值。
*b=20;// b為右值,*b為左值。

左值->右值:用&符號。

int a = 10;
&a = 40; //錯誤:賦值操作要求一個左值
int* b = &(a + 1); //錯誤:‘&'運運算元要求一個左值,a為左值,但a+1為右值。
int* c = &a; //正確:var是左值

左值參照:將左值繫結在參照上

第一種情況,函數返回右值。

int global = 10;
int test()
{
return global;// 返回右值
}
int main()
{
test() = 20;// error,右值不可賦值!
cout << "test為:"<<test();
return 0;
}

第二種情況,函數返回左值。

int global = 10;
int& test()
{
return global;// 返回左值
}
int main()
{
test() = 20;// 左值可賦值
cout << "test為:"<<test();
return 0;
}

測試:

說明了左值參照讓函數呼叫可以賦值成為可能。

常數左值參照和非常數左值參照

int a1=20; //非常數左值
const int a2=20; //常數左值
const int a3=20; //常數左值

//非常數左值參照
int &b1=a1; //正確,a1是一個非常數左值,可以被非常數左值參照系結
int &b2=a2; //錯誤,a2是一個常數左值,不可以被非常數左值參照系結
int &b3=20; //錯誤,10是一個非常數右值,不可以被非常數左值參照系結
int &b4=a2+a3; //錯誤,(a2+a3)是一個常數右值,不可以被非常數左值參照系結

//常數左值參照
const int &c1=a1; //正確,a1是一個非常數左值,可以被非常數右值參照系結
const int &c2=a2; //正確,a2是一個常數左值,可以被非常數右值參照系結
const int &c3=a1+a2; //正確,(a1+a2)是一個非常數右值,可以被常數右值參照系結
const int &c4=a2+a3; //正確,(a2+a3)是一個常數右值,可以被非常數右值參照系結

總結:

  • 1.非常數左值參照只能繫結到非常數左值上;
  • 2.常數左值參照可以繫結到非常數左值、常數左值、非常數右值、常數右值等所有型別。

(大->小,小參照綁大左值,常數左值範圍更小嘛)

右值參照:將右值繫結在參照上

常數右值參照和非常數右值參照

總結:

  • 1.非常數右值參照只能繫結到非常數右值上;
  • 2.常數右值參照可以繫結到非常數右值、常數右值上。

移動建構函式

小狗狗類:

Dog(int age,string name) :m_age(new int(age)), m_name(name){}
Dog(Dog& d):m_age(d.m_age),m_name(d.m_name)
{
cout << "我是拷貝建構函式······" << endl;
}
Dog(Dog&& d) :m_age(d.m_age), m_name(d.m_name)
{
d.m_age = nullptr;
cout << "我是移動建構函式······" << endl;
}
int* m_age;
string m_name;#include<string>
#include<iostream>
using namespace std;
class Dog
{
public:
Dog(){};
Dog(int age,string name) :m_age(new int(age)), m_name(name){}
Dog(Dog& d):m_age(d.m_age),m_name(d.m_name)
{
cout << "我是拷貝建構函式······" << endl;
}
Dog(Dog&& d) :m_age(d.m_age), m_name(d.m_name)
{
d.m_age = nullptr;
cout << "我是移動建構函式······" << endl;
}
int* m_age;
string m_name;
};

使用者端類:

#include"construct.h"
int main()
{
int age = 19;
string name = "小狗狗";
Dog d1(age, name);
cout << "d1:" <<* d1.m_age << d1.m_name << endl;
Dog d2(move(d1));
bool is = d1.m_age == nullptr;
cout << is << endl;
cout << "d2.age:" << *d2.m_age <<endl<< "d2.name:" <<d2.m_name << endl;
return 0;
}

測試:

說明了移動構造執行成功,d1銷燬了,d2獲取到了d1的記憶體。

賦值和移動賦值函數

賦值函數類:

#include<String>
using namespace std;
class Cat
{
public:
Cat(){}
Cat(int age ,string name):age(age),name(name) {}
Cat& operator=(Cat& c)
{
if (this!= &c)
{
age = c.age;
name = c.name;
}
return *this;
}
int age;
string name;
};

移動賦值函數類:

#include"assign.h"
class Dog
{
public:
Dog() {}
Dog(int age, string name) :age(new int(age)), name(name) {}

Dog& operator=(Dog&& c)
{
age = c.age;
name = c.name;
c.age = nullptr;
return *this;
}
int* age;
string name;
};

使用者端類:

#include<iostream>
#include"moveAssign.h"
int main()
{
cout << "賦值函數" << endl;
Cat c1(18, "小貓咪");
Cat c2 ;
c2 = c1;
cout << "c1.age:" << c1.age << endl << "c1.name" << c1.name << endl;
cout << "c2.age:" << c2.age << endl << "c2.name" << c2.name << endl<<endl;;
cout << "移動賦值函數" << endl;
Dog d1(19,"小狗狗");
cout << "d1.age:" << *d1.age << endl << "d1.name" << d1.name << endl << endl;
Dog d2;
d2 = move(d1);
bool is = (d1.age == nullptr);
cout << "d1是否為空:" << is << endl;
cout << "d2.age:" << *d2.age << endl << "d2.name" << d2.name << endl;
return 0;
}

測試:

到此這篇關於C++賦值函數+移動賦值函數+移動建構函式詳解的文章就介紹到這了,更多相關C++賦值函數 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com