一、構(gòu)造函數(shù)
- C++規(guī)定,每個(gè)類必須有默認(rèn)的構(gòu)造函數(shù),沒有構(gòu)造函數(shù)就不能創(chuàng)建對(duì)象。
- 若沒有提供任何構(gòu)造函數(shù),那么c++提供自動(dòng)提供一個(gè)默認(rèn)的構(gòu)造函數(shù),該默認(rèn)構(gòu)造函數(shù)是一個(gè)沒有參數(shù)的構(gòu)造函數(shù),它僅僅負(fù)責(zé)創(chuàng)建對(duì)象而不做任何賦值操作。
- 只要類中提供了任意一個(gè)構(gòu)造函數(shù),那么c++就不在自動(dòng)提供默認(rèn)構(gòu)造函數(shù)。
- 類對(duì)象的定義和變量的定義類似,使用默認(rèn)構(gòu)造函數(shù)創(chuàng)建對(duì)象的時(shí)候,如果創(chuàng)建的是靜態(tài)或者是全局對(duì)象,則對(duì)象的位模式全部為0,否則將會(huì)是隨即的。
#include<iostream>
class Student{
public:
Student(){//無參數(shù)構(gòu)造函數(shù)
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
};
void Student::show(){
cout<<number<<endl<<score<<endl;
}
void main()
{
Student a;
a.show();
cin.get();
}
- 在類中的定義和類名相同,并且沒有任何返回類型的Student()就是構(gòu)造函數(shù),這是一個(gè)無參數(shù)的構(gòu)造函數(shù),他再對(duì)象創(chuàng)建的時(shí)候自動(dòng)調(diào)用,如果去掉 Student()函數(shù)體內(nèi)的代碼那么它和 C++默認(rèn)提供的構(gòu)造函數(shù)是等價(jià)的。
- 構(gòu)造函數(shù)可以帶任意多個(gè)形式的參數(shù),這一點(diǎn)和普通函數(shù)的特性是一樣的!下面是一個(gè)帶參數(shù)的構(gòu)造函數(shù):
#include<iostream>
using namespace std;
class Teacher
{
public:
Teacher(char * input_name)//有參數(shù)的構(gòu)造函數(shù)
{
name = new char[10];
//name = input_name;//這樣賦值是錯(cuò)誤的
strcpy(name,input_name);
}
void show();
protected:
char *name;
}
void Teacher::show()
{
cout<<name<<endl;
}
void main()
{
//Teacher a;//這里是錯(cuò)誤的,因?yàn)闆]有無參數(shù)的構(gòu)造函數(shù)
Teacher a("test");
a.show();
cin.get();
}
-
兩個(gè)注意:
- 我們創(chuàng)建了一個(gè)帶有字符指針的帶有形參的 Teacher(char *input_name) 的構(gòu)造函數(shù),調(diào)用它創(chuàng)建對(duì)象的使用類名加對(duì)象名稱加擴(kuò)號(hào)和擴(kuò)號(hào)內(nèi)參數(shù)的方式調(diào)用,這和調(diào)用函數(shù)有點(diǎn)類似,但意義也有所不同,因?yàn)?構(gòu)造函數(shù)是為創(chuàng)建對(duì)象而設(shè)立的,這里的意義不單純是調(diào)用函數(shù),而是創(chuàng)建一個(gè)類對(duì)象。
一旦類中有了一個(gè)帶參數(shù)的構(gòu)造函數(shù)而又沒有無參數(shù)構(gòu)造函數(shù)的時(shí)候系統(tǒng)無法創(chuàng)建不帶參數(shù)的 Teacher a; - //name = input_name;//這樣賦值是錯(cuò)誤的
因?yàn)?name 指是指向內(nèi)存堆區(qū)的,如果使用 name = input_name; 會(huì)造成指針指向改變不是指向堆區(qū)而是指向棧區(qū),導(dǎo)致在后面調(diào)用析構(gòu)函數(shù) delete 釋放空間出錯(cuò)!
- 我們創(chuàng)建了一個(gè)帶有字符指針的帶有形參的 Teacher(char *input_name) 的構(gòu)造函數(shù),調(diào)用它創(chuàng)建對(duì)象的使用類名加對(duì)象名稱加擴(kuò)號(hào)和擴(kuò)號(hào)內(nèi)參數(shù)的方式調(diào)用,這和調(diào)用函數(shù)有點(diǎn)類似,但意義也有所不同,因?yàn)?構(gòu)造函數(shù)是為創(chuàng)建對(duì)象而設(shè)立的,這里的意義不單純是調(diào)用函數(shù),而是創(chuàng)建一個(gè)類對(duì)象。
#include <iostream>
using namespace std;
class Teacher
{
public:
Teacher(char *input_name)
{
name=new char[10];
//name=input_name;//這樣賦值是錯(cuò)誤的
strcpy(name,input_name);
}
Teacher()//無參數(shù)構(gòu)造函數(shù),進(jìn)行函數(shù)重載
{
}
void show();
protected:
char *name;
};
void Teacher::show()
{
cout<<name<<endl;
}
void main()
{
Teacher test;
Teacher a("test");
a.show();
cin.get();
}
- 創(chuàng)建一個(gè)無參數(shù)的同名的 Teacher()無參數(shù)函數(shù),一重載方式區(qū)分調(diào)用,由于構(gòu)造函數(shù)和普通函數(shù)一樣具有重載特性所以編寫程序的人可以給一個(gè)類添加任意多個(gè)構(gòu)造函數(shù),來使用不同的參數(shù)來進(jìn)行初始化對(duì)象。
- C++規(guī)定如果一個(gè)類對(duì)象是另外一個(gè)類的數(shù)據(jù)成員,那么在創(chuàng)建對(duì)象的時(shí)候系統(tǒng)將自動(dòng)調(diào)用哪個(gè)類的構(gòu)造函數(shù)。
#include <iostream>
using namespace std;
class Teacher
{
public:
Teacher()
{
director = new char[10];
strcpy(director,"王大力");
}
char * show();
protected:
char * director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student()
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher;//這個(gè)類的成員teacher是用Teacher類進(jìn)行創(chuàng)建并初始化的
};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl;
}
void main()
{
Student a;
a.show();
Student b[3];
for(int i=0; i<sizeof(b)/sizeof(Student); i++)
{
b[i].show();
}
cin.get();
}
- 上面代碼中的Student類成員中teacher成員是的定義是用類Teacher進(jìn)行定義創(chuàng)建的,那么系統(tǒng)碰到創(chuàng)建代碼的時(shí)候就會(huì)自動(dòng)調(diào)用Teacher類中的Teacher()構(gòu)造函數(shù)對(duì)對(duì)象進(jìn)行初始化工作!
- 這個(gè)例子說明類的分工很明確,只有碰到自己的對(duì)象的創(chuàng)建的時(shí)候才自己調(diào)用自己的構(gòu)造函數(shù)。
二、析構(gòu)函數(shù)
一個(gè)類可能需要在構(gòu)造函數(shù)內(nèi)動(dòng)態(tài)分配資源,那么這些動(dòng)態(tài)開辟的資源就需要在對(duì)象不復(fù)存在之前被銷毀掉,那么c++類的析構(gòu)函數(shù)就提供了這個(gè)方便。
析構(gòu)函數(shù)的定義:**析構(gòu)函數(shù)也是特殊的類成員函數(shù),它沒有返回類型,沒有參數(shù),不能隨意調(diào)用,也沒有重載,只有在類對(duì)象的生命期結(jié)束的時(shí)候,由系統(tǒng)自動(dòng)調(diào)用。 **
析構(gòu)函數(shù)與構(gòu)造函數(shù)的不同:析構(gòu)函數(shù)與構(gòu)造函數(shù)最主要大不同就是在于調(diào)用期不同,構(gòu)造函數(shù)可以有參數(shù)可以重載!
-
如何編寫析構(gòu)函數(shù):
- 析構(gòu)函數(shù)可以的特性是在程序結(jié)束的時(shí)候逐一調(diào)用,那么正好與構(gòu)造函數(shù)的情況是相反,屬于互逆特性,所以定義析構(gòu)函數(shù)因使用“~”符號(hào)(邏輯非運(yùn)算符),標(biāo)示它為逆構(gòu)造函數(shù),加上類名稱來定義。
#include <iostream>
#include <string>
using namespace std;
class Teacher
{
public:
Teacher()
{
director = new char[10];
strcpy(director,"王大力");
//director = new string;
// *director="王大力";//string情況賦值
}
~Teacher()
{
cout<<"釋放堆區(qū)director內(nèi)存空間1次";
delete[] director;
cin.get();
}
char *show();
protected:
char *director;
//string *director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student()
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher;
};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl;
}
void main()
{
Student a;
a.show();
Student b[3];
for(int i=0; i<sizeof(b)/sizeof(Student); i++)
{
b[i].show();
}
cin.get();
}
- 上面的代碼中我們?yōu)門eacher類添加了一個(gè)名為~Teacher()的析構(gòu)函數(shù)用于清空堆內(nèi)存。
- 程序?qū)⒃诮Y(jié)束前也就是對(duì)象聲明周期結(jié)束的時(shí)候自動(dòng)調(diào)用~Teacher()。
- 有直接的關(guān)系,以后能為 delete 操作符只能清空堆空間而不能夠清除棧空間,如果強(qiáng)行清除??丶?nèi)存的畫將導(dǎo)致程序的崩潰!
#include <iostream>
#include <string>
using namespace std;
class Teacher
{
public:
Teacher(char *temp)
{
director = new char[10];
strcpy(director,temp);
}
~Teacher()
{
cout<<"釋放堆區(qū)director內(nèi)存空間1次";
delete[] director;
cin.get();
}
char *show();
protected:
char *director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student()
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher("王大力");//錯(cuò)誤,一個(gè)類的成員如果是另外一個(gè)類的對(duì)象的話,不能在類中使用帶參數(shù)的構(gòu)造函數(shù)進(jìn)行初始化
};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl;
}
void main()
{
Student a;
a.show();
Student b[3];
for(int i=0; i<sizeof(b)/sizeof(Student); i++)
{
b[i].show();
}
cin.get();
}
這樣不行,程序不能夠編譯成功,
因?yàn)椋?strong>類是一個(gè)抽象的概念,并不是一個(gè)實(shí)體,并不能包含屬性值,只有對(duì)象才占有一定的內(nèi)存空間,含有明確的屬性值。
- C++的解決方案是叫構(gòu)造類成員。
#include <iostream>
using namespace std;
class Teacher
{
public:
Teacher(char *temp)
{
director = new char[10];
strcpy(director,temp);
}
~Teacher()
{
cout<<"釋放堆區(qū)director內(nèi)存空間1次";
delete[] director;
cin.get();
}
char *show();
protected:
char *director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student(char *temp):teacher(temp)
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher;
};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl;
}
void main()
{
Student a("王大力");
a.show();
//Student b[3]("王大力"); //這里這么用是不對(duì)的,數(shù)組不能夠使用帶參數(shù)的構(gòu)造函數(shù),以后我們將詳細(xì)介紹vector類型
// for(int i=0; i<sizeof(b)/sizeof(Student); i++)
//{
// b[i].show();
//}
cin.get();
}
- 最明顯的改變?cè)谶@里
Student(char *temp):teacher(temp)
冒號(hào)后的 teacher 就是要告訴調(diào)用 Student 類的構(gòu)造函數(shù)的時(shí)候把參數(shù)傳遞給成員 teacher 的 Teacher 類的構(gòu)造函數(shù),這樣一來我們就成功的在類體外對(duì) teacher 成員進(jìn)行了初始化,既方便也搞笑,這種冒號(hào)后制定調(diào)用某成員構(gòu)造函數(shù)的方式,可以同時(shí)制定多個(gè)成員,這一特性使用都好方式,例如:
Student(char *temp):teacher(temp),abc(temp),def(temp)
修改一下代碼:
#include <iostream>
#include <string>
using namespace std;
class Teacher
{
public:
Teacher(char *temp)
{
director = new char[10];
strcpy(director,temp);
}
~Teacher()
{
cout<<"釋放堆區(qū)director內(nèi)存空間1次";
delete[] director;
cin.get();
}
char *show();
protected:
char *director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student(char *temp,int &pk):teacher(temp),pk(pk),ps(10)
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher;
int &pk;
const int ps;
};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl<<pk<<endl<<ps<<endl;
}
void main()
{
char *t_name="王大力";
int b=99;
Student a(t_name,b);
a.show();
cin.get();
}
- 調(diào)用的時(shí)候我們使用 :
Student a(t_name,b);
- 我們將b的地址傳遞給了int &pk這個(gè)引用,使得Student類的引用成員pk和常量成員ps進(jìn)行了成功的初始化。
但是細(xì)心的人會(huì)發(fā)現(xiàn),我們?cè)谶@里使用的初始化方式并不是在構(gòu)造函數(shù)內(nèi)進(jìn)行的,而是在外部進(jìn)行初始化的,的確,在冒號(hào)后和在構(gòu)造函數(shù)括號(hào)內(nèi)的效果是一樣的, 但和teacher(temp)所不同的是,pk(pk)的括號(hào)不是調(diào)用函數(shù)的意思,而是賦值的意思,我想有些讀者可能不清楚新標(biāo)準(zhǔn)的 C++對(duì)變量的初始 化是允許使用括號(hào)方式的,int a=10和int a(10)的等價(jià)的,但冒號(hào)后是不允許使用=方式只允許()括號(hào)方式,所以這里只能使用pk(pk)而不能是pk=pk了。
***c++規(guī)定,所有的全局對(duì)象和全局變量一樣都在主函數(shù)main()之前被構(gòu)造,函數(shù)體內(nèi)的靜態(tài)對(duì)象則只構(gòu)造一次,也就是說只在首次進(jìn)入這個(gè)函數(shù)的時(shí)候進(jìn)行構(gòu)造! ***
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
Test(int a)
{
kk=a;
cout<<"構(gòu)造參數(shù)a:"<<a<<endl;
}
public:
int kk;
};
void fun_t(int n)
{
static Test a(n);
//static Test a=n;//這么寫也是對(duì)的
cout<<"函數(shù)傳入?yún)?shù)n:"<<n<<endl;
cout<<"對(duì)象a的屬性kk的值:"<<a.kk<<endl;
}
Test m(100);
void main()
{
fun_t(20);
fun_t(30);
cin.get();
}
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
Test(int a)
{
kk=a;
cout<<"構(gòu)造參數(shù)a:"<<a<<endl;
}
public:
int kk;
};
void fun_t(int n)
{
static Test a(n);
//static Test a=n;//這么寫也是對(duì)的
cout<<"函數(shù)傳入?yún)?shù)n:"<<n<<endl;
cout<<"對(duì)象a的屬性kk的值:"<<a.kk<<endl;
}
Test m(100);
void main()
{
fun_t(20);
fun_t(30);
cin.get();
}
#include <iostream>
using namespace std;
class Test
{
public:
Test(int j):pb(j),pa(pb+5)
{
}
public:
int pa;
int pb;
};
void main()
{
Test a(10);
cout<<a.pa<<endl;
cout<<a.pb<<endl;
cin.get();
}
類成員的構(gòu)造是按照在類中定義的順序進(jìn)行的,而不是按照構(gòu)造函數(shù)說明后的冒號(hào)順序進(jìn)行構(gòu)造的。
三、Q&A
- delete 某個(gè)類的指針會(huì)調(diào)用該類的析構(gòu)函數(shù)么?
會(huì)的.如果不調(diào)用的話怎么析構(gòu)一個(gè)類.
不過指針?biāo)赶虻膶?duì)象必須是在堆中用new關(guān)鍵詞開創(chuàng)的
如果指針指向的是一個(gè)棧中的對(duì)象,會(huì)引起調(diào)用兩種析構(gòu)函數(shù)而導(dǎo)致程序錯(cuò)誤
class ob
ob a;
ob *p=&a;
delete p;//這樣會(huì)導(dǎo)致調(diào)用兩次析構(gòu)函數(shù).是會(huì)引起程序錯(cuò)誤的
只有
class ob
ob * p= new ob;
delete p; //這樣是正確的
對(duì)于 new 創(chuàng)建的對(duì)象,只有調(diào)用 delete 才能析構(gòu)。
-
構(gòu)造函數(shù):
- 什么是構(gòu)造函數(shù)?通俗的講,在類中,函數(shù)名和類名相同的函數(shù)稱為構(gòu)造函數(shù)。它的作用是在建立一個(gè)對(duì)象時(shí),作某些初始化的工作(例如對(duì)數(shù)據(jù)賦予初值)。C++允許同名函數(shù),也就允許在一個(gè)類中有多個(gè)構(gòu)造函數(shù)。如果一個(gè)都沒有,編譯器將為該類產(chǎn)生一個(gè)默認(rèn)的構(gòu)造函數(shù)。
構(gòu)造函數(shù)上惟一的語法限制是它不能指定返回類型,甚至void 也不行。
不帶參數(shù)的構(gòu)造函數(shù):一般形式為 類名 對(duì)象名(){函數(shù)體}
帶參數(shù)的構(gòu)造函數(shù):不帶參數(shù)的構(gòu)造函數(shù),只能以固定不變的值初始化對(duì)象。帶參數(shù)構(gòu)造函數(shù)的初始化要靈活的多,通過傳遞給構(gòu)造函數(shù)的參數(shù),可以賦予對(duì)象不同的初始值。一般形式為:構(gòu)造函數(shù)名(形參表);
創(chuàng)建對(duì)象使用時(shí):類名 對(duì)象名(實(shí)參表);
構(gòu)造函數(shù)參數(shù)的初始值:構(gòu)造函數(shù)的參數(shù)可以有缺省值。當(dāng)定義對(duì)象時(shí),如果不給出參數(shù),就自動(dòng)把相應(yīng)的缺省參數(shù)值賦給對(duì)象。一般形式為:
構(gòu)造函數(shù)名(參數(shù)=缺省值,參數(shù)=缺省值,……);
- 什么是構(gòu)造函數(shù)?通俗的講,在類中,函數(shù)名和類名相同的函數(shù)稱為構(gòu)造函數(shù)。它的作用是在建立一個(gè)對(duì)象時(shí),作某些初始化的工作(例如對(duì)數(shù)據(jù)賦予初值)。C++允許同名函數(shù),也就允許在一個(gè)類中有多個(gè)構(gòu)造函數(shù)。如果一個(gè)都沒有,編譯器將為該類產(chǎn)生一個(gè)默認(rèn)的構(gòu)造函數(shù)。
-
析構(gòu)函數(shù):
- 當(dāng)一個(gè)類的對(duì)象離開作用域時(shí),析構(gòu)函數(shù)將被調(diào)用(系統(tǒng)自動(dòng)調(diào)用)。析構(gòu)函數(shù)的名字和類名一樣,不過要在前面加上 ~ 。對(duì)一個(gè)類來說,只能允許一個(gè)析構(gòu)函數(shù),析構(gòu)函數(shù)不能有參數(shù),并且也沒有返回值。析構(gòu)函數(shù)的作用是完成一個(gè)清理工作,如釋放從堆中分配的內(nèi)存。
一個(gè)類中可以有多個(gè)構(gòu)造函數(shù),但析構(gòu)函數(shù)只能有一個(gè)。對(duì)象被析構(gòu)的順序,與其建立時(shí)的順序相反,即后構(gòu)造的對(duì)象先析構(gòu)。
- 當(dāng)一個(gè)類的對(duì)象離開作用域時(shí),析構(gòu)函數(shù)將被調(diào)用(系統(tǒng)自動(dòng)調(diào)用)。析構(gòu)函數(shù)的名字和類名一樣,不過要在前面加上 ~ 。對(duì)一個(gè)類來說,只能允許一個(gè)析構(gòu)函數(shù),析構(gòu)函數(shù)不能有參數(shù),并且也沒有返回值。析構(gòu)函數(shù)的作用是完成一個(gè)清理工作,如釋放從堆中分配的內(nèi)存。