深入講解C++中的構造函數

深入講解C++中的構造函數,這篇文章主要介紹了C++中的構造函數,是C++入門學習中的基礎知識,需要的朋友可以參考下
關鍵字:C++、構造函數

C++構造函數
當創建一個對象時,往往需要做一些初始化工作,例如對數據成員賦值等。為了解決這個問題,C++提供了構造函數。

構造函數(Constructor)是一種特殊的成員函數,它的名字和類名相同,沒有返回值,不需要用戶調用(用戶也不能調用),而是在創建對象時自動執行。構造函數的作用是在創建對象時進行初始化工作,最常見的就是對成員變量賦值。

一個構造函數的例子:

#include <iostream>
using namespace std;
class Student{
private:
  char *name;
  int age;
  float score;
public:
  //聲明構造函數
  Student(char *, int, float);
  //聲明普通成員函數
  void say();
};
//定義構造函數
Student::Student(char *name1, int age1, float score1){
  name = name1;
  age = age1;
  score = score1;
}
//定義普通成員函數
void Student::say(){
  cout<<name<<"的年齡是 "<<age<<",成績是 "<<score<<endl;
}
int main(){
  //根據構造函數創建對象
  Student stu("小明", 15, 90.5f); //傳參形式類似于函數調用
  stu.say();
  return 0;
}

運行結果:

小明的年齡是 15,成績是 90.5

在類中我們定義了一個構造函數 Student(),它的作用是給3個 private 屬性的成員變量賦值。在 main 函數中,我們根據構造函數創建了一個對象 stu;因為構造函數有參數,所以創建對象時要相應地傳入實參,形式類似于函數調用。

讀者要注意:一旦在類中定義了構造函數,那么創建對象時一定會被執行;如果構造函數有參數,創建對象時就要傳參。

另外,構造函數主要用來進行初始化,沒有返回值(有返回值沒有任何意義),這就意味著:
不管是聲明還是定義,函數名前面都不能出現返回值類型,即使是 void 也不允許;
函數體中不能有 return 語句。
默認構造函數

如果用戶自己沒有定義構造函數,那么編譯器會自動生成一個默認的構造函數,只是這個構造函數的函數體是空的,也沒有參數,不執行任何操作。比如上面的 Student 類,默認生成的構造函數如下:

Student(){}


一個類,必須有構造函數,要么用戶自己定義,要么編譯器自動生成。一旦用戶自己定義了構造函數,不管它是 public 屬性的,還是 private、protected 屬性的,編譯器都不再自動生成。上面的 Student 類,只有一個構造函數,就是我們自己定義的。
實際上,編譯器只有在必要的時候才會生成默認構造函數,而且它的函數體一般不為空。默認構造函數的目的是幫助編譯器做初始化工作,而不是幫助程序員。這是C++的內部實現機制,這里不再深究,初學者可以按照上面說的“一定有一個空函數體的默認構造函數”來理解。
構造函數的重載

和普通成員函數一樣,構造函數是允許重載的。一個類可以提供多個構造函數,讓用戶在創建對象時進行選擇,編譯器會根據創建對象時傳遞的參數來確定調用哪一個構造函數。也就是說:
只有一個構造函數會被執行;
創建對象時提供的參數必須和其中的一個構造函數匹配,否則編譯錯誤。

一個構造函數重載的例子:

#include <iostream>
using namespace std;
class Student{
private:
  char *name;
  int age;
  float score;
public:
  //聲明構造函數
  Student();
  Student(char *, int, float);
  //聲明普通成員函數
  void setname(char *);
  void setage(int);
  void setscore(float);
  void say();
};
//定義構造函數
Student::Student(){}
Student::Student(char *name1, int age1, float score1){
  name = name1;
  age = age1;
  score = score1;
}
//定義普通成員函數
void Student::setname(char *name1){
  name = name1;
}
void Student::setage(int age1){
  age = age1;
}
void Student::setscore(float score1){
  score = score1;
}
void Student::say(){
  cout<<name<<"的年齡是 "<<age<<",成績是 "<<score<<endl;
}
int main(){
  //創建對象時初始化成員變量
  Student stu1("小明", 15, 90.5f);
  stu1.say();
  
  //調用成員函數來初始化成員變量的值
  Student stu2;
  stu2.setname("李磊");
  stu2.setage(16);
  stu2.setscore(95);
  stu2.say();
  return 0;
}

運行結果:

小明的年齡是 15,成績是 90.5
李磊的年齡是 16,成績是 95

類中定義了兩個構造函數,一個帶參數一個不帶參數,它們是重載關系。當根據不帶參數的構造函數創建對象時,不需要傳參,成員變量不會被初始化,所以要調用成員函數來設置它們的值。

C++帶參數的構造函數
不帶參數的構造函數使該類的每一個對象都得到相同的初始值。

如果希望對不同的對象賦予不同的初始值,則需要使用帶參數的構造函數,在調用不同對象的構造函數時,將不同的數據傳給構造函數,以實現不同的初始化。

構造函數首部的一般格式為:
 

  構造函數名(類型1 形參1, 類型2 形參2, …)


由于用戶是不能調用構造函數的,因此無法采用常規的調用函數的方法給出實參。實參是在創建對象時給出的。創建對象的一般格式為:

  類名 對象名(實參1, 實參2, …);

【例】有兩個長方柱,其長、寬、高分別為12, 20, 25和10, 14, 20,求它們的體積。編寫一個基于對象的程序,在類中用帶參數的構造函數。

#include <iostream>
using namespace std;
class Box
{
  public :
  Box(int,int,int);
  int volume( );
  private :
  int height;
  int width;
  int length;
};
//聲明帶參數的構造函數//聲明計算體積的函數
Box::Box(int h,int w,int len) //在類外定義帶參數的構造函數
{
  height=h;
  width=w;
  length=len;
}
int Box::volume( ) //定義計算體積的函數
{
  return (height*width*length);
}
int main( )
{
  Box box1(12,25,30); //建立對象box1,并指定box1長、寬、高的值
  cout<<"The volume of box1 is "<<box1.volume( )<<endl;
  Box box2(15,30,21); //建立對象box2,并指定box2長、寬、高的值
  cout<<"The volume of box2 is "<<box2.volume( )<<endl;
  return 0;
}

程序運行結果如下:

The volume of box1 is 9000
The volume of box2 is 9450

可以知道:
帶參數的構造函數中的形參,其對應的實參在定義對象時給定。
用這種方法可以方便地實現對不同的對象進行不同的初始化。
用參數初始化表對數據成員初始化

上面介紹的是在構造函數的函數體內通過賦值語句對數據成員實現初始化。C++還提供另一種初始化數據成員的方法——參數初始化表來實現對數據成員的初始化。這種方法不在函數體內對數據成員初始化,而是在函數首部實現。

例中定義構造函數可以改用以下形式:

  Box::Box(int h,int w,int len):height(h),width(w), length(len){ }


這種寫法方便、簡練,尤其當需要初始化的數據成員較多時更顯其優越性。甚至可以直接在類體中(而不是在類外)定義構造函數。

众人帮太赚钱了