程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> c++中拷貝結構函數的參數類型必需是援用

c++中拷貝結構函數的參數類型必需是援用

編輯:關於C++

c++中拷貝結構函數的參數類型必需是援用。本站提示廣大學習愛好者:(c++中拷貝結構函數的參數類型必需是援用)文章只能為提供參考,不一定能成為您想要的結果。以下是c++中拷貝結構函數的參數類型必需是援用正文


在C++中, 結構函數,拷貝結構函數,析構函數和賦值函數(賦值運算符重載)是最根本不外的須要控制的常識。 然則假如我問你“拷貝結構函數的參數為何必需應用援用類型?”這個成績, 你會怎樣答復? 也許你會答復為了削減一次內存拷貝? 很忸捏的是,我的第一感到也是這麼答復。不外還好,我思考一下今後,發明這個謎底是纰謬的。

緣由:
假如拷貝結構函數中的參數不是一個援用,即形如CClass(const CClass c_class),那末就相當於采取了傳值的方法(pass-by-value),而傳值的方法會挪用該類的拷貝結構函數,從而形成無限遞歸地挪用拷貝結構函數。是以拷貝結構函數的參數必需是一個援用。

須要廓清的是,傳指針其實也是傳值,假如下面的拷貝結構函數寫成CClass(const CClass* c_class),也是不可的。現實上,只要傳援用不是傳值外,其他一切的傳遞方法都是傳值。
先從一個小例子開端:(本身測試一下本身看看這個法式的輸入是甚麼?)

#include<iostream>
using namespace std;
class CExample
{
private:
 int m_nTest;
public:
 CExample(int x) : m_nTest(x)      //帶參數結構函數
 {
  cout << "constructor with argument"<<endl;
 }
 // 拷貝結構函數,參數中的const不是嚴厲必需的,但援用符號是必需的
 CExample(const CExample & ex)     //拷貝結構函數
 {
  m_nTest = ex.m_nTest;
  cout << "copy constructor"<<endl;
 }
 CExample& operator = (const CExample &ex)   //賦值函數(賦值運算符重載)
 { 
  cout << "assignment operator"<<endl;
  m_nTest = ex.m_nTest;
  return *this;
 }
 void myTestFunc(CExample ex)
 {
 }
};
int main(void)
{
 CExample aaa(2);
 CExample bbb(3);
 bbb = aaa;
 CExample ccc = aaa;
 bbb.myTestFunc(aaa);
 return 0; 
}

果你能一眼看出就是這個成果的話, 祝賀你,可以站起來扭扭屁股,不消再往下看了。
假如你的成果和輸入成果有誤差, 那請托你謙遜的看完。
第一個輸入: constructor with argument      // CExample aaa(2);
假如你不睬解的話, 找小我把你拖出去痛打一頓,然後嘴裡還喊著“我是二師兄,我是二師兄.......”
第二個輸入:constructor with argument     // CExample bbb(3);
剖析同第一個
第三個輸入: assignment operator                // bbb = aaa;
第四個輸入: copy constructor                      // CExample ccc = aaa;
這兩個得放到一塊說。 確定會有人問為何兩個紛歧致。緣由是, bbb對象曾經實例化了,不須要結構,此時只是將aaa賦值給bbb,只會挪用賦值函數,就這麼簡略,還不懂的話,撞牆去! 然則ccc還沒有實例化,是以挪用的是拷貝結構函數,結構出ccc,而不是賦值函數,還不懂的話,我撞牆去!!
第五個輸入: copy constructor                      //  bbb.myTestFunc(aaa);
現實上是aaa作為參數傳遞給bbb.myTestFunc(CExample ex), 即CExample ex = aaa;和第四個分歧的, 所以照樣拷貝結構函數,而不是賦值函數, 假如依然不懂, 我的頭適才曾經流血了,不要再讓我撞了,你就本身用力的再裝一次吧。
經由過程這個例子, 我們來剖析一下為何拷貝結構函數的參數只能應用援用類型。
看第四個輸入: copy constructor                      // CExample ccc = aaa;
結構ccc,本質上是ccc.CExample(aaa); 我們假設拷貝結構函數參數不是援用類型的話, 那末將使得 ccc.CExample(aaa)釀成aaa傳值給ccc.CExample(CExample ex),即CExample ex = aaa,由於 ex 沒有被初始化, 所以 CExample ex = aaa 持續挪用拷貝結構函數,接上去的是結構ex,也就是 ex.CExample(aaa),必定又會有aaa傳給CExample(CExample ex), 即 CExample ex = aaa;那末又會觸發拷貝結構函數,就這下永久的遞歸下去。
所以繞了那末年夜的彎子,就是想解釋拷貝結構函數的參數應用援用類型不是為了削減一次內存拷貝, 而是防止拷貝結構函數無窮制的遞歸下去。

附帶解釋,鄙人面幾種情形下會挪用拷貝結構函數:
a、顯式或隱式地用同類型的一個對象來初始化別的一個對象。如上例中,用對象c初始化d;
b、作為實參(argument)傳遞給一個函數。如CClass(const CClass c_class)中,就會挪用CClass的拷貝結構函數;
c、在函數體內前往一個對象時,也會挪用前往值類型的拷貝結構函數;
d、初始化序列容器中的元素時。好比 vector<string> svec(5),string的缺省結構函數和拷貝結構函數都邑被挪用;
e、用列表的方法初始化數組元素時。string a[] = {string(“hello”), string(“world”)}; 會挪用string的拷貝結構函數。

假如在沒有顯式聲明結構函數的情形下,編譯器都邑為一個類分解一個缺省的結構函數。假如在一個類中聲清楚明了一個結構函數,那末就會阻攔編譯器為該類分解缺省的結構函數。和結構函數分歧的是,即使界說了其他結構函數(但沒有界說拷貝結構函數),編譯器老是會為我們分解一個拷貝結構函數。

別的函數的前往值是否是援用也有很年夜的差別,前往的不是援用的時刻,只是一個簡略的對象,此時須要挪用拷貝結構函數,不然,假如是援用的話就不須要挪用拷貝結構函數。

#include<iostream>
using namespace std;
class A
{
private:
 int m_nTest;
public:
 A()
 {
 }
 A(const A& other)    //結構函數重載
 {
  m_nTest = other.m_nTest;
  cout << "copy constructor"<<endl; 
 }
 A & operator =(const A& other)
 {
  if(this != &other)
  {
   m_nTest = other.m_nTest;
   cout<<"Copy Assign"<<endl;
  }
  return *this;
 }
};
A fun(A &x)
{
 return x;     //前往的不是援用的時刻,須要挪用拷貝結構函數
}
int main(void)
{
 A test;
 fun(test);
 system("pause");
 return 0;
}

分享一道口試標題,編譯運轉下圖中的C++代碼,成果是甚麼?(A)編譯毛病;(B)編譯勝利,運轉時法式瓦解;(C)編譯運轉正常,輸入10。請選擇准確謎底並剖析緣由。

class A
{
private:
 int value;
public:
 A(int n)
 {
  value = n;
 }
 A(A other)
 {
  value = other.value;
 }
 void Print()
 {
  cout<<value<<endl;
 }
};
int main(void)
{
 A a = 10;
 A b = a;
 b.Print();
 return 0;
}

謎底:編譯毛病。在復制結構函數中傳入的參數是A的一個實例。因為是傳值,把形參拷貝到實參會挪用復制結構函數。是以假如許可復制結構函數傳值,那末會構成永無停止的遞合並形成棧溢出。是以C++的尺度不許可復制結構函數傳值參數,而必需是傳援用或許常量援用。在Visual Studio和GCC中,都將編譯失足。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved