程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 完整控制C++編程中結構函數應用的超等進修教程

完整控制C++編程中結構函數應用的超等進修教程

編輯:關於C++

完整控制C++編程中結構函數應用的超等進修教程。本站提示廣大學習愛好者:(完整控制C++編程中結構函數應用的超等進修教程)文章只能為提供參考,不一定能成為您想要的結果。以下是完整控制C++編程中結構函數應用的超等進修教程正文


結構函數是一種可初始化其類的實例的成員函數。結構函數具有與類雷同的稱號,沒有前往值。結構函數可以具有隨意率性數目的參數,類可以具有隨意率性數目的重載結構函數。結構函數可以具有任何可拜訪性(公共、受掩護或公有)。假如不決義任何結構函數,則編譯器會生成不采取任何參數的默許結構函數;可以經由過程將默許結構函數聲明為已刪除來重寫此行動。
結構函數次序
結構函數按此次序履行任務:
按聲明次序挪用基類和成員結構函數。
假如類派生自虛擬基類,則會將對象的虛擬基指針初始化。
假如類具有或繼續了虛函數,則會將對象的虛函數指針初始化。虛函數指針指向類中的虛函數表,確保虛函數准確地挪用綁定代碼。
它履行本身函數體中的一切代碼。
上面的示例顯示,在派生類的結構函數中,基類和成員結構函數的挪用次序。起首,挪用基結構函數,然後依照基類成員在類聲明中湧現的次序對這些成員停止初始化,然後,挪用派生結構函數。

#include <iostream>
using namespace std;

class Contained1 {
public:
  Contained1() {
    cout << "Contained1 constructor." << endl;
  }
};

class Contained2 {
public:
  Contained2() {
    cout << "Contained2 constructor." << endl;
  }
};

class Contained3 {
public:
  Contained3() {
    cout << "Contained3 constructor." << endl;
  }
};

class BaseContainer {
public:
  BaseContainer() {
    cout << "BaseContainer constructor." << endl;
  }
private:
  Contained1 c1;
  Contained2 c2;
};

class DerivedContainer : public BaseContainer {
public:
  DerivedContainer() : BaseContainer() {
    cout << "DerivedContainer constructor." << endl;
  }
private:
  Contained3 c3;
};

int main() {
  DerivedContainer dc;
  int x = 3;
}

這是輸入:

Contained1 constructor.
Contained2 constructor.
BaseContainer constructor.
Contained3 constructor.
DerivedContainer constructor.

假如結構函數激發異常,析構的次序與結構的次序相反:
結構函數主體中的代碼將睜開。
基類和成員對象將被燒毀,次序與聲明次序相反。
假如長短拜托結構函數,一切完整結構的基類對象和成員均將被燒毀。然則,對象自己不是完整結構的,是以析構函數不會運轉。
成員列表
應用成員初始值設定項列表從結構函數參數初始化類成員。此辦法應用直接初始化,這比在結構函數體內應用賦值運算符更高效。

class Box {
public:
  Box(int width, int length, int height) 
    : m_width(width), m_length(length), m_height(height) // member init list
  {}
  int Volume() {return m_width * m_length * m_height; }
private:
  int m_width;
  int m_length;
  int m_height;

};

創立 Box 對象:

Box b(42, 21, 12);
cout << "The volume is " << b.Volume();

顯式結構函數
假如類具有帶一個參數的結構函數,或是假如除一個參數以外的一切參數都具有默許值,則參數類型可以隱式轉換為類類型。例如,假如 Box 類具有一個相似於上面如許的結構函數:

Box(int size): m_width(size), m_length(size), m_height(size){}

可以初始化 Box,以下所示:

Box b = 42;

或將一個 int 傳遞給采取 Box 的函數:

class ShippingOrder
{
public:
  ShippingOrder(Box b, double postage) : m_box(b), m_postage(postage){}

private:
  Box m_box;
  double m_postage;
}
//elsewhere...
  ShippingOrder so(42, 10.8);


這類轉換能夠在某些情形下很有效,但更罕見的是,它們能夠會招致代碼中產生纖細但嚴重的毛病。作為普通規矩,應對結構函數應用 explicit 症結字(和用戶界說的運算符)以避免湧現這類隱式類型轉換:

explicit Box(int size): m_width(size), m_length(size), m_height(size){}

結構函數是顯式函數時,此行會招致編譯器毛病:ShippingOrder so(42, 10.8);。
默許結構函數
默許結構函數沒有參數;它們遵守略有分歧的規矩:
默許結構函數是一個特別成員函數;假如沒有在類中聲明結構函數,則編譯器會供給默許結構函數:

class Box {
  Box(int width, int length, int height) 
    : m_width(width), m_length(length), m_height(height){}
};

int main(){

  Box box1{}; // call compiler-generated default ctor
  Box box2;  // call compiler-generated default ctor
}

當你挪用默許結構函數並測驗考試應用括號時,體系將收回正告:

class myclass{};
int main(){
myclass mc();   // warning C4930: prototyped function not called (was a variable definition intended?)
}

這是“最辣手的解析”成績的示例。這類示例表達式既可以說明為函數的聲明,也能夠說明為對默許結構函數的挪用,並且 C++ 剖析器更傾向於聲明,是以表達式會被視為函數聲明。
假如聲清楚明了任何非默許結構函數,編譯器不會供給默許結構函數:

class Box {
  Box(int width, int length, int height) 
    : m_width(width), m_length(length), m_height(height){}
};
private:
  int m_width;
  int m_length;
  int m_height;

};

int main(){

  Box box1(1, 2, 3);
  Box box2{ 2, 3, 4 };
  Box box4;   // compiler error C2512: no appropriate default constructor available
}

假如類沒有默許結構函數,將沒法經由過程零丁應用方括號語法來結構該類的對象數組。例如,在後面提到的代碼塊中,框的數組沒法停止以下聲明:

Box boxes[3];  // compiler error C2512: no appropriate default constructor available

然則,你可使用初始值設定項列表將框的數組初始化:

Box boxes[3]{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

復制和挪動結構函數
復制結構函數是特別成員函數,它采取對雷同類型對象的援用作為輸出,並創立它的正本。挪動也是特別成員函數結構函數,它將現有對象的一切權移交給新變量,而不復制原始數據。

顯式默許結構函數和已刪除結構函數
你可以顯式設置默許復制結構函數、設置默許結構函數、挪動結構函數、復制賦值運算符、挪動賦值運算符和析構函數。你可以顯式刪除一切特別成員函數。
派生類中的結構函數
派生類結構函數一直挪用基類結構函數,是以,在完成任何額定義務之前,它可以依附於完整結構的基類。挪用基類結構函數停止派生,例如,假如 ClassA 派生自 ClassB,ClassB 派生自 ClassC,那末起首挪用 ClassC 結構函數,然後挪用 ClassB 結構函數,最初挪用 ClassA 結構函數。
假如基類沒有默許結構函數,則必需在派生類結構函數中供給基類結構函數參數:

class Box {
public:
  Box(int width, int length, int height){
    m_width = width;
    m_length = length;
    m_height = height;
  }

private:
  int m_width;
  int m_length;
  int m_height;
};

class StorageBox : public Box {
public:
  StorageBox(int width, int length, int height, const string label&) : Box(width, length, height){
    m_label = label;
  }
private:
  string m_label;
};

int main(){

  const string aLabel = "aLabel";
  StorageBox sb(1, 2, 3, aLabel);
} 

具有多重繼續的類的結構函數
假如類從多個基類派生,那末將依照派生類聲明中列出的次序挪用基類結構函數:

#include <iostream>
using namespace std;

class BaseClass1 {
public:
  BaseClass1() {
    cout << "BaseClass1 constructor." << endl;
  }
};
class BaseClass2 {
public:
  BaseClass2() {
    cout << "BaseClass2 constructor." << endl;
  }
};
class BaseClass3{
public:
  BaseClass3() {
    cout << "BaseClass3 constructor." << endl;
  }
};
class DerivedClass : public BaseClass1, public BaseClass2, public BaseClass3 {
public:
  DerivedClass() {
    cout << "DerivedClass constructor." << endl;
  }
};

int main() {
  DerivedClass dc;
}

你應看到以下輸入:

BaseClass1 constructor.
BaseClass2 constructor.
BaseClass3 constructor.
DerivedClass constructor.

結構函數中的虛函數
我們建議你謹嚴挪用結構函數中的虛函數。基類結構函數一直在派生類結構函數之前挪用,是以基結構函數中挪用的函數是基類版本,而非派生類版本。鄙人面的示例中,結構 DerivedClass 會招致履行 BaseClass 的 print_it() 完成早於 DerivedClass 結構函數招致履行 DerivedClass 的 print_it() 完成:

#include <iostream>
using namespace std;

class BaseClass{
public:
  BaseClass(){
    print_it();
  }
  virtual void print_it() {
    cout << "BaseClass print_it" << endl;
  }
};

class DerivedClass : public BaseClass {
public:
  DerivedClass() {
    print_it();
  }
  virtual void print_it(){
    cout << "Derived Class print_it" << endl;
  }
};

int main() {

  DerivedClass dc;
}

這是輸入:

BaseClass print_it
Derived Class print_it

結構函數和復合類
包括類類型成員的類稱為“復合類”。創立復合類的類類型成員時,挪用類本身的結構函數之前,先挪用結構函數。當包括的類沒有默許結構函數是,必需應用復合類結構函數中的初始化列表。在之前的 StorageBox 示例中,假如將 m_label 成員變量的類型更改成新的 Label 類,則必需挪用基類結構函數,而且將 m_label 變量(位於 StorageBox 結構函數中)初始化:

class Label {
public:
  Label(const string& name, const string& address) { m_name = name; m_address = address; }
  string m_name;
  string m_address;
};

class StorageBox : public Box {
public:
  StorageBox(int width, int length, int height, Label label) 
    : Box(width, length, height), m_label(label){}
private:
  Label m_label;
};

int main(){
// passing a named Label
  Label label1{ "some_name", "some_address" };
  StorageBox sb1(1, 2, 3, label1);

  // passing a temporary label
  StorageBox sb2(3, 4, 5, Label{ "another name", "another address" });

  // passing a temporary label as an initializer list
  StorageBox sb3(1, 2, 3, {"myname", "myaddress"});
}

拜托結構函數
拜托結構函數挪用統一類中的其他結構函數,完成部門初始化任務。鄙人面的示例中,派生類具有三個結構函數,第二個結構函數拜托第一個,第三個結構函數拜托第二個:

#include <iostream>
using namespace std;

class ConstructorDestructor {
public:
  ConstructorDestructor() {
    cout << "ConstructorDestructor default constructor." << endl;
  }
  ConstructorDestructor(int int1) {
    cout << "ConstructorDestructor constructor with 1 int." << endl;
  }
  ConstructorDestructor(int int1, int int2) : ConstructorDestructor(int1) {
    cout << "ConstructorDestructor constructor with 2 ints." << endl;

    throw exception();
  }
  ConstructorDestructor(int int1, int int2, int int3) : ConstructorDestructor(int1, int2) {
    cout << "ConstructorDestructor constructor with 3 ints." << endl;
  }
  ~ConstructorDestructor() {
    cout << "ConstructorDestructor destructor." << endl;
  }
};

int main() {
  ConstructorDestructor dc(1, 2, 3);
}

這是輸入:

ConstructorDestructor constructor with 1 int.
ConstructorDestructor constructor with 2 ints.
ConstructorDestructor constructor with 3 ints.

一切結構函數完成後,完整初始化的結構函數將立刻創立對象。 DerivedContainer(int int1) 勝利,然則 DerivedContainer(int int1, int int2) 掉敗,並挪用析構函數。

class ConstructorDestructor {
public:
  ConstructorDestructor() {
    cout << "ConstructorDestructor default constructor." << endl;
  }
  ConstructorDestructor(int int1) {
    cout << "ConstructorDestructor constructor with 1 int." << endl;
  }
  ConstructorDestructor(int int1, int int2) : ConstructorDestructor(int1) {
    cout << "ConstructorDestructor constructor with 2 ints." << endl;
    throw exception();
  }
  ConstructorDestructor(int int1, int int2, int int3) : ConstructorDestructor(int1, int2) {
    cout << "ConstructorDestructor constructor with 3 ints." << endl;
  }

  ~ConstructorDestructor() {
    cout << "ConstructorDestructor destructor." << endl;
  }
};

int main() {

  try {
    ConstructorDestructor cd{ 1, 2, 3 };
  }
  catch (const exception& ex){
  }
}

輸入:

ConstructorDestructor constructor with 1 int.
ConstructorDestructor constructor with 2 ints.
ConstructorDestructor destructor.

繼續結構函數 (C++11)
派生類可使用 using 聲明從直接基類繼續結構函數,以下面的示例所示:

#include <iostream>
using namespace std;

class Base
{
public:  
  Base() { cout << "Base()" << endl; }
  Base(const Base& other) { cout << "Base(Base&)" << endl; }
  explicit Base(int i) : num(i) { cout << "Base(int)" << endl; }
  explicit Base(char c) : letter(c) { cout << "Base(char)" << endl; }

private:
  int num;
  char letter;
};

class Derived : Base
{
public:
  // Inherit all constructors from Base
  using Base::Base;

private:
  // Can't initialize newMember from Base constructors.
  int newMember{ 0 };
};


int main(int argc, char argv[])
{
  cout << "Derived d1(5) calls: "; 
  Derived d1(5);
  cout << "Derived d1('c') calls: ";
  Derived d2('c');
  cout << "Derived d3 = d2 calls: " ;
  Derived d3 = d2;
  cout << "Derived d4 calls: ";
  Derived d4; 

  // Keep console open in debug mode:
  cout << endl << "Press Enter to exit.";
  char in[1];
  cin.getline(in, 1);
  return 0;
}

輸入:
Derived d1(5) calls: Base(int)
Derived d1('c') calls: Base(char)
Derived d3 = d2 calls: Base(Base&)
Derived d4 calls: Base()
Press Enter to exit.

using 語句可未來自基類的一切結構函數引入規模(除簽名與派生類中的結構函數雷同的結構函數)。普通而言,當派生類未聲明新數據成員或結構函數時,最好應用繼續結構函數。
假如類型指定基類,則類模板可以從類型參數繼續一切結構函數:

template< typename T >
class Derived : T {
  using T::T;  // declare the constructors from T
  // ...
};

假如基類的結構函數具有雷同簽名,則派生類沒法從多個基類繼續。
聲明結構函數的規矩
結構函數與它的類的稱號雷同。可以聲明隨意率性數目的結構函數,這取決於重載函數的規矩。

argument-declaration-list 能夠為空。
C++ 界說兩種特別的結構函數(默許結構函數和復制結構函數),以下表所述。

默許結構函數和復制結構函數

默許結構函數可在沒有參數的情形下挪用。然則,假如一切參數都有默許值,則可以用參數列表聲明默許結構函數。異樣,復制結構函數必需接收對雷同類類型的援用的單一參數。可以供給多個參數,條件是一切後續參數都有默許值。
假如未供給任何結構函數,則編譯器將測驗考試生成默許結構函數。假如未供給復制結構函數,則編譯器將測驗考試生成一個。這些編譯器生成的結構函數被視為公共成員函數。假如應用屬於對象但不屬於援用的第一個參數指定復制結構函數,則將生成毛病。
編譯器生成的默許結構函數將設置對象(如上文所述,初始化 vftables 和 vbtables),並挪用基類和成員的默許結構函數,然則它不履行任何其他操作。僅當基類和成員結構函數存在、可拜訪而且無歧義時才會挪用它們。
編譯器生成的復制結構函數將設置新的對象,並對要復制的對象的內容按成員復制。假如基類或成員結構函數存在,則將挪用它們;不然將履行按位復制。
假如類 type 的一切基類和成員類均具有接收 const 參數的復制結構函數,則編譯器生成的復制結構函數將接收 const type& 類型的單個參數。不然,編譯器生成的復制結構函數將接收 type& 類型的單個參數。
您可使用結構函數初始化 const 或 volatile 對象,然則,結構函數自己不克不及聲明為 const 或 volatile。結構函數的獨一正當存儲類是 inline;將任何其他存儲類潤飾符(包含 __declspec 症結字)與結構函數一路應用將招致編譯器毛病。
stdcall 挪用商定用於應用 __stdcall 症結字聲明的靜態成員函數和全局函數,且不應用變量參數列表。對非靜態成員函數(如結構函數)應用 __stdcall 症結字時,編譯器將應用 thiscall 挪用商定。
基類的結構函數不由派生類繼續。創立派生類類型的對象時,該對象將從基類組件開端停止結構;然後移到派生類組件。因為全部對象有一部門已初始化,是以編譯器應用每一個基類的結構函數(虛擬派生的情形除外,如初始化基類中所述)。
顯式挪用結構函數
可以在法式中顯式挪用結構函數來創立給定類型的對象。例如,若要創立描寫某行末尾的兩個 Point 對象,請編寫以下代碼:

DrawLine( Point( 13, 22 ), Point( 87, 91 ) );

創立類型 Point 的兩個對象,將其傳遞給函數 DrawLine,並在表達式(函數挪用)的末尾將其燒毀。
在個中顯式挪用結構函數的另外一個高低文正在停止初始化:

Point pt = Point( 7, 11 );

應用接收類型為 Point 的兩個參數的結構函數來創立和初始化類型為 int 的對象。
經由過程顯式挪用結構函數創立的對象(如下面的兩個示例)未停止定名,而且該對象具有在個中創立它們的表達式的生計期。 暫時對象中更具體地評論辯論了這一點。
平日,從結構函數的外部挪用一切成員函數是平安的,由於該對象在用戶代碼的第一行履行之前已完整設置(已初始化虛擬表等)。然則,在結構或析構時代,成員函數挪用籠統基類的虛擬成員函數能夠是不平安的。
結構函數可以挪用虛函數。挪用虛函數時,挪用的函數將是為結構函數本身的類界說的函數(或從其基類繼續)。以下示例演示從結構函數的外部挪用虛函數時產生的情形:

// specl_calling_virtual_functions.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;
class Base
{
public:
  Base();       // Default constructor.
  virtual void f();  // Virtual member function.
};

Base::Base()
{
  cout << "Constructing Base sub-object\n";
  f();        // Call virtual member function
}            // from inside constructor.

void Base::f()
{
  cout << "Called Base::f()\n";
}

class Derived : public Base
{
public:
  Derived();     // Default constructor.
  void f();      // Implementation of virtual
};           // function f for this class.

Derived::Derived()
{
  cout << "Constructing Derived object\n";
}

void Derived::f()
{
  cout << "Called Derived::f()\n";
}

int main()
{
  Derived d;
}

在運轉後面的法式時,聲明 Derived d 將發生以下事宜序列:
挪用類 Derived (Derived::Derived) 的結構函數。
在輸出 Derived 類的結構函數的主體之前,挪用類 Base (Base::Base) 的結構函數。
Base::Base 挪用函數 f,該函數是一個虛函數。平日,將挪用 Derived::f,由於對象 d 屬於類型 Derived。因為 Base::Base 函數是結構函數,是以該對象不屬於 Derived 類型,而且將挪用 Base::f。

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