C++構造函數—構造函數的聲明與定義、帶參數的構造函數
2020-05-23 14:26:00
供稿:網友
構造函數是一種隨著對象創建而自動被調用的函數,它的主要用途是為對象作初始化。那么,構造函數到底是什么樣子的呢?
構造函數的聲明與定義
在C++中,規定與類同名的成員函數就是構造函數。需要注意的是,構造函數應該是一個公有的成員函數,并且構造函數沒有返回值類型。以下是我們為鏈表結點類編寫的一個構造函數:(其他成員函數定義見14.3節)
//node.h
#include <iostream>//如果不包含iostream頭文件,這個文件里就不能用cout
using namespace std;
class Node//定義一個鏈表結點類
{
public:
……
Node();//構造函數的聲明,構造函數是公有的成員函數,沒有返回值類型
……
private:
int idata;//存儲數據保密
char cdata;//存儲數據保密
Node *prior;//前驅結點的存儲位置保密
Node *next;//后繼結點的存儲位置保密
};
Node::Node()//構造函數的定義
{
cout <<"Node constructor is running..." <<endl;//提示構造函數運行
idata=0;//初始化idata
cdata='0';//初始化cdata
prior=NULL;//初始化前驅結點指針
next=NULL;//初始化后續結點指針
}
這時,我們創建一個鏈表結點對象,構造函數隨著對象創建而自動被調用,所以這個對象創建之后idata的值為0,cdata的值為'0',prior和next的值都是NULL:(程序15.2.1)
//main.cpp
#include <iostream>
#include "node.h"
using namespace std;
int main()
{
Node a;//創建一個鏈表結點對象a,調用構造函數
cout <<a.readi() <<endl;
cout <<a.readc() <<endl;
return 0;
}
運行結果:
Node constructor is running...
0
0
可是,這樣的構造函數還是不太理想。如果每次初始化的值都是固定的,那么有沒有構造函數都是一樣的。構造函數變成了一種擺設!我們該怎么辦?
帶參數的構造函數
函數的特征之一就是能夠在調用時帶上參數。既然構造函數也是函數,那么我們就能給構造函數帶上參數,使用重載或默認參數等方法,從而實現更自由地對對象進行初始化操作。以下便是對鏈表結點類的進一步修改:(程序15.2.2)
//node.h
#include <iostream>
using namespace std;
class Node//定義一個鏈表結點類
{
public:
Node();//構造函數0
Node(int i,char c='0');//構造函數重載1,參數c默認為'0'
Node(int i,char c,Node *p,Node *n);//構造函數重載2
int readi() const;//讀取idata
char readc() const;//讀取cdata
Node * readp() const;//讀取上一個結點的位置
Node * readn() const;//讀取下一個結點的位置
bool set(int i);//重載,通過該函數修改idata
bool set(char c);//重載,通過該函數修改cdata
bool setp(Node *p);//通過該函數設置前驅結點
bool setn(Node *n);//通過該函數設置后繼結點
private:
int idata;//存儲數據保密
char cdata;//存儲數據保密
Node *prior;//前驅結點的存儲位置保密
Node *next;//后繼結點的存儲位置保密
};
int Node::readi() const//成員函數readi的定義
{
return idata;
}
char Node::readc() const
{
return cdata;
}
Node * Node::readp() const
{
return prior;
}
Node * Node::readn() const
{
return next;
}
bool Node::set(int i)//重載成員函數定義
{
idata=i;
return true;
}
bool Node::set(char c)
{
cdata=c;
return true;
}
bool Node::setp(Node *p)
{
prior=p;
return true;
}
bool Node::setn(Node *n)
{
next=n;
return true;
}
Node::Node()//構造函數0的定義
{
cout <<"Node constructor is running..." <<endl;//提示構造函數運行
idata=0;//初始化idata
cdata='0';//初始化cdata
prior=NULL;//初始化前驅結點指針
next=NULL;//初始化后續結點指針
}
Node::Node(int i,char c)//構造函數重載1,默認參數只需要在函數原型中出現
{
cout <<"Node constructor is running..." <<endl;
idata=i;
cdata=c;
prior=NULL;
next=NULL;
}
Node::Node(int i,char c,Node *p,Node *n)//構造函數重載2
{
cout <<"Node constructor is running..." <<endl;
idata=i;
cdata=c;
prior=p;
next=n;
}
//main.cpp
#include <iostream>
#include "node.h"
using namespace std;
int main()
{
Node a;//創建一個鏈表結點對象a,調用構造函數0
Node b(8);//創建一個鏈表結點對象b,調用構造函數重載1,參數c默認為'0'
Node c(8,'F',NULL,NULL);//創建一個鏈表結點對象c,調用構造函數重載2
cout <<a.readi() <<' ' <<a.readc() <<endl;
cout <<b.readi() <<' ' <<b.readc() <<endl;
cout <<c.readi() <<' ' <<c.readc() <<endl;
return 0;
}
運行結果:
Node constructor is running...
Node constructor is running...
Node constructor is running...
0 0
8 0
8 F
我們看到,在參數和重載的幫助下,我們可以設計出適合各種場合的構造函數。初始化各個對象的成員數據對我們來說已經是小菜一碟了。但是,這時你是否會回想起當初沒有編寫構造函數時的情形?如果沒有編寫構造函數,對象的創建是一個怎樣的過程呢?
在C++中,每個類都有且必須有構造函數。如果用戶沒有自行編寫構造函數,則C++自動提供一個無參數的構造函數,稱為默認構造函數。這個默認構造函數不做任何初始化工作。一旦用戶編寫了構造函數,則這個無參數的默認構造函數就消失了。如果用戶還希望能有一個無參數的構造函數,必須自行編寫。