在生活中我們購買單電子產品通常都會有出廠設置,在某一天我們不用也會刪除一些自己的數據信息以保證安全。
c++中的面向對象來源於生活,每個對象也都會有初始設置以及對象銷毀清理數據的設置。
1.構造函數和析構函數
對象的初始化和清理也是兩個非常重要的安全問題:
- 一個對象或者變量沒有初始狀態,對其使用后結果未知。
- 同樣的使用完一個對象或者變量,沒有及時清理,也會造成一定的安全問題。
c++利用了構造函數和析構函數解決上述問題,這兩個函數將會被編譯器自動調用,完成對象初始化和清理工作。對象的初始化和清理工作是編譯器強制我們做的事情,因此如果我們不提供構造函數和析構函數,編譯器會提供編譯器提供的構造函數和析構函數的空實現。
什么是構造函數?
主要作用於創建對象時為對象的成員屬性進行賦值。
什么是析構函數?
主要作用於對象在銷毀時執行一些清理工作。
構造函數語法:類名(){}
- 構造函數,沒有返回值也不寫void
- 函數名與類名相同
- 構造函數可以有參數,因此可以重載
- 程序在創建對象時會自動調用構造函數,而且只會調用一次
析構函數語法:~類名(){}
- 析構函數,沒有返回值也不寫void
- 函數名與類名相同,在名稱前面jiahsang~
- 構造函數不可以有參數,因此不能重載
- 程序在對象銷毀時會自動調用析構函數,而且只會調用一次
#include<iostream> using namespace std; class Student { string name; int age; double score; public: //構造函數 Student(){ cout << "調用構造函數" << endl; } //析構函數 ~Student() { cout << "調用析構函數" << endl; } }; void test() { //在棧上的數據,test執行完畢之后就會被釋放 Student s; } int main() { test(); system("pause"); return 0; }
2.構造函數的分類以及調用
兩種分類方式:有參構造、無參構造;普通構造、拷貝構造;
三種調用方式:括號法、顯示法、隱式替換法;
#include<iostream> using namespace std; class Student { string name; int age; double score; public: //無參構造函數 Student(){ cout << "調用Student()構造函數" << endl; } //有參構造函數 Student(string name,int age) { cout << "調用Student(string name,int age)構造函數" << endl; } //拷貝構造函數 Student(const Student &stu) { name = stu.name; age = stu.age; score = stu.score; cout << "調用拷貝構造函數" << endl; } //析構函數 ~Student() { cout << "調用Student()析構函數" << endl; } }; void test() { //匿名對象,當前行運行完后就會調用析構函數 //不要使用拷貝構造函數初始化匿名對象:Student(s2); Student(); //隱式三種形式 cout << "隱式調用" << endl; Student s1; Student s2{"tom",12}; Student s3{ s2 }; //顯示三種形式 cout << "顯示調用" << endl; Student s4 = Student(); Student s5 = Student("bo",22); Student s6 = Student(s5); //隱式轉換法,相當於Student s7 = Student{ "mike",17 }; Student s7 = { "mike",17 }; } int main() { test(); system("pause"); return 0; }
輸出:
3.拷貝構造函數的調用時機
c++拷貝構造函數調用時有三種情況:
- 使用一個已經創建完畢的對象來初始化一個新對象;
- 值傳遞的方式給函數參數傳輸;
- 以值方式返回局部對象;
即這三種情況下都會調用拷貝構造函數。
#include<iostream> using namespace std; class Person { public: int m_age; public: Person() { cout << "Person默認構造函數" << endl; } Person(int age) { m_age = age; cout << "Person(int age)構造函數" << endl; } Person(const Person& p) { m_age = p.m_age; cout << "拷貝構造函數" << endl; } ~Person() { cout << "Person析構函數" << endl; } }; //使用一個已經創建完畢的對象來初始化一個新對象 void test() { Person p1(22); Person p2(p1); cout << "p2的年齡是:" << p2.m_age << endl; } void doWork(Person p) {} //使用值傳遞的方式 void test2() { Person p; doWork(p); } //值返回局部對象 Person doWork2() { Person p1; return p1; } void test3() { Person p = doWork2(); } int main() { test3(); system("pause"); return 0; }
4.構造函數的調用規則
默認情況下,c++編譯器至少會給一個類添加三個函數:
- 默認無參構造函數
- 默認析構函數;
- 默認拷貝構造函數,對屬性進行值拷貝;
構造函數調用規則如下:
- 如果用戶自定義構造函數,c++不再提供無參構造函數,但是會提供拷貝構造函數;
- 如果用戶自定義拷貝構造函數,c++不會再提供其它構造函數;
