一、默認構造函數html
默認構造函數是指全部參數都提供了默認值的構造函數,一般指無參的構造函數或提供默認值的構造函數。如類Test1和Test2的構造函數ios
class Test1 { public: Test1(){} // default constructor } ; 或 class Test2 { public: Test2(int i=1){} // default constructor } ;
若是你沒有爲你的類提供任何構造函數,那麼編譯器將自動爲你生成一個默認的無參構造函數。一旦你爲你的類定義了構造函數,哪怕只是一個,那麼編譯器將再也不生成默認的構造函數。程序員
二、什麼時候須要爲你的類提供默認構造函數編程
有不少狀況,列舉以下:數組
1. 當你使用靜態分配的數組,而數組元素類型是某個類的對象時,就要調用默認的構造函數,好比下面的代碼。app
Object buffer[10]; // call default constructor
2. 當你使用動態分配的數組,而數組元素類型是某個類的對象時,就要調用默認的構造函數,好比下面的代碼,若是Object沒有默認的構造函數,是沒法經過編譯的,由於new操做符要調用Object類的無參構造函數類初始化每一個數組元素。框架
Object* buffer = new Object[10];
3. 當你使用標準庫的容器時,若是容器內的元素類型是某個類的對象時,那麼這個類就須要默認的構造函數,緣由同上。編程語言
vector<Object> buffer;
4. 一個類A以另外某個類B的對象爲成員時,若是A提供了無參構造函數,而B未提供,那麼A則沒法使用本身的無參構造函數。下面的代碼將致使編譯錯誤。函數
class B { B(int i){} }; class A { A(){} B b; }; int main(void) { A a(); // error C2512: 'B' : no appropriate default constructor available getchar() ; return 0 ; }
再好比下面的代碼,類A定義了拷貝構造函數,而沒有提供默認的構造函數,B繼承自A,因此B在初始化時要調用A的構造函數來初始化A,而A沒有默認的構造函數,故產生編譯錯誤。ui
class A { A(const A&){} }; class B : public A { }; int main(void) { B b; //error C2512:'B': no appropriate default constructor available getchar() ; return 0 ; }
除以上狀況以外還有不少,不在此一一舉例描述。
參考自:http://www.cnblogs.com/graphics/archive/2012/10/02/2710340.html
當咱們新建了一個Qt的widgets應用工程時。會自動生成一個框架,包含了幾個文件。其中有個mainwindow.h的頭文件。就是你要操縱的UI主界面了。咱們看看其中的一段代碼:
class MainWindow : public QMainWindow { Q_OBJECT//一個宏,暫不考慮 public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; };
這段代碼定義了一個新的類MainWindow,繼承自QMainWindow。咱們能夠看到在它的構造函數裏,前面有一個關鍵字 explicit 。相信你們都對沒有這個關鍵字的構造函數不陌生。那麼這個 explicit 是起到什麼做用的呢?
explicit是C++中的關鍵字,不是C語言中的。英文直譯是「明確的」、「顯式的」意思。出現這個關鍵字的緣由,是在C++中有這樣規定的基礎上: 當定義了只有一個參數的構造函數時,同時也定義了一種隱式的類型轉換。 先看類型轉換。
C/C++中,有不少類型轉換。好比:
double a = 12.34; int b = (int)a;
咱們都知道這時b的值是12. 在變量前面加括號包裹的類型,就能實現顯式的類型轉換。這種叫作強制類型轉換。順便值得一提的是,C++中還支持這種強制類型轉換的例子:
double a = 12.34; int b = int(a);
除此以外,還有一種轉換叫作 隱式類型轉換。
double a = 12.34; int b = a;
一樣的,b的值也是12.雖然沒有顯式的轉換類型,可是編譯器會幫你自動轉換。一樣的,不只是基本數據類型,本身定義的類和對象之間也存在這種轉換關係。
好比你有一個類的對象A:
class A { public: A(int i) { a = i; } int getValue() { return a; }; private: int a; };
你會發現,你在main函數中,使用下面的語句時是合法的:
A a = 10;
之因此類A的對象能夠直接使用整型經過等於號來初始化,是由於這一語句調用了默認的單參數構造函數,其效果等價於 A temp(10); a(temp);
首先編譯器執行A temp(10);在棧中建立了一個臨時對象(假設叫作temp)。而後再調用對象a的拷貝初始化構造函數 a(temp) 給a初始化。而後臨時對象temp銷燬。這就是編譯器作的隱式轉換工做。你能夠想到這樣的隱式操做的結果和直接顯示調用A a(10);的結果是同樣的,可是隱式轉換由於使用了拷貝構造函數因此在開銷上會更高一些。固然這基本數據類型,或許不明顯。若是一個複雜的對象,好比Qt的窗口。那麼開銷可想而知。
又如當你使用以下語句會不經過:
A a = "123";
由於沒有參數爲字符串的單參數構造函數。知道了這個,你修改一下就能經過了。
class A { public: A(int i) { a = i; } A(char * c) { a=c[0]; } int getValue() { return a; }; private: int a; };
咱們再定義一個函數print 用來打印A對象的值。
void print(A a) { cout<<a.getValue(); };
在main函數中:
void main() { print(10); }
這樣是能夠編譯運行的。雖然咱們並無建立一個類A的對象來傳給print 函數。可是編譯器默認會調用類A的單參數構造函數,建立出一個類A的對象出來。
上面能夠看出編譯器會爲你作一些,隱式的類型轉換工做。這或許會讓你感到方便,可是有時候卻會帶來麻煩。咱們來作一個假設:
上面這個類A,只接受整型和字符串型。因此你想傳遞一個字符串 「2」 做爲參數來構造一個新的對象。好比 A b = 「2」; 然而,你卻寫錯了,雙引號寫成了單引號變成了 A b = ‘2’; 然而這樣並不會報錯。編譯器 會把 字符 ‘2’ 轉型成 整型 也就是它的ascll碼—— 50。爲了不這樣咱們不但願的隱式轉換,咱們能夠加上explicit 關鍵字。
public: explicit A(int i) { a=i; }
這樣就能避免隱式的類型轉換了,當你誤寫成單引號的時候,就會報錯。這樣就只容許顯示的調用單參數構造函數了。如 A a(10); A b("123");
不只如此,在加上explicit以後,print函數也會報錯了。由於編譯器不會主動調用explicit標識的構造器。這就須要你本身顯示的來調用了:
print(A(10));
固然了,是否應該禁止隱式轉換是沒有定論的,沒有一種放之四海皆準的標準,具體看你的情景須要了。
explicit使用注意事項:
* explicit 關鍵字只能用於類內部的構造函數聲明上。
* explicit 關鍵字做用於單個參數的構造函數(或者除了第一個參數外其他參數都有默認值的多參構造函數),如Circle(int x, int y = 0) 。
* 在C++中,explicit關鍵字用來修飾類的構造函數,被修飾的構造函數的類,不能發生相應的隱式類型轉換,只能以顯示的方式進行類型轉換。
explicit關鍵字只用在類內部的聲明中。在外部的實現部分不須要使用。
#include<iostream> using namespace std; class A { public: explicit A(int i); A(char * c) { a=c[0]; } int getValue() { return a; }; private: int a; }; A::A(int i)//無需再指明explicit { a=i; } void print(A a) { cout<<a.getValue(); }; void main() { print(A(10)); }
轉自:http://blog.csdn.net/guodongxiaren/article/details/24455653?utm_source=tuicool&utm_medium=referral