顯示初始化、隱式初始化和賦值
最近看了不少關於初始化和賦值的文章,其中提到最多的是要分清楚什么是賦值,什么是初始化,下面的例子都是初始化,也就是顯示初始化和隱式初始化:
C++隱式初始化
int ival(1024);
string hello("Hello world.")
C++顯式初始化
int ival = 1024;
string hello = "Hello world."
Note: 注意這里"=" 語法是調用拷貝構造函數而不是賦值運算,也就是這是一個初始化操作,而不是賦值操作,因為賦值操作是在一個對象已經存在的情況下進行的,而這里在=那句話之前對象並不存在。下面是賦值的例子:
string hello;
hello = "Hello world"; <- 這里hello 已經被定義了,才是賦值操作.
隱式和顯示類型轉換
先搞清楚什么是隱式類型轉換,什么是顯示類型轉換吧!所謂隱式類型轉換就是隱藏的,代碼中並不有語句進行轉換,但是編譯器會隱式做類型轉換以滿足一些特定語句的需要,比如:int i = i +d;(i是int,d是double),這里發生的隱式轉換包括,先將i轉為double,和d相加,然后把i+d的結果轉成int。更概括來說,隱式類型轉換發生在以下4中情況中:
- 在混合類型的算術表達式中
int ival = 3;
double dval = 3.1415
ival + dval; //ival 被提升為double 類型:3.0 - 用另外一種類型的表達式賦值
int *pi = NULL; // NULL(0)被轉換成了int* 類型的空指針值 - 用一個表達式傳遞給一個函數調用
extern double sqrt(double);
sqrt(2); //2被提升為double類型: 2.0 - 從一個函數返回一個表達式
double difference(int ival1, int ival2)
{
return ival1 - ival2; //返回值被提升為double 類型.
}
C++內建類型(char,int,short,double,etc.)對像之間默認含有隱式轉換,C++的自定義類對象之間可以含有隱式轉換,隱式轉換有兩種形式:從其他類型向自身轉換,從自身向其他類型轉換。從其他類型向自身轉換是由下面的conversion constructor完成的,這個conversion constructor也是構造函數的一種,因為只有一個參數而變成了conversion constructor,但有時我們不想這個構造函數變成conversion constructor,就可以加explicit來明確禁止進行隱式類型轉換; 從自身向其他類型轉換就是由隱式類型轉換操作符完成的。
C++顯式轉換包含四種轉換:
- static_cast : 編譯期的轉化,不能轉換掉expression的const、volitale、或者__unaligned屬性
- 所有內建類型對象之間的隱式轉換都可用static_cast.
- 把空指針轉換成目標類型的空指針用static_cast。
- 把任何類型的表達式轉換成void類型用static_cast。
- 類層次間的上行轉換和下行轉換也可以用static_cast,但下行轉換即當把基類指針或引用轉換成子類表示時,由於沒有動態類型檢查,所以是不安全的.反之是安全的.
- dynamic_cast : 運行期的轉換,類層次間的上行轉換和下行轉換
- dynamic_cast具有類型檢查的功能,下行轉換的效果跟static_cast是一樣的,但下行轉換比static_cast更安全。
- dynamic_cast還支持交叉轉換,兩個類如果有共同的祖先,他們的指針就可以用dynamic_cast.
- const_cast : 編譯期的轉化,類型中的常量
- reinterpret_cast : 任何指針都可以轉換成其它類型的指針,可用於如char* 到 int*,或者One_class* 到 Unrelated_class* 等的轉換,因此可能是不安全的。
在這里,需要特別說明一下static_cast,對於用戶自定義的類型static_cast會調用用戶自定義的類型轉換操作符,如果用戶沒有定義類型轉換操作符,static_cast會失敗,比如類A和類B沒有關系,但是強制調用static_cast,編譯器會報告:error: no matching function for call to B::B(A&)。C++11開始支持explicit的類型轉換符,也就是這個類型轉換符必須通過static_cast調用。
Conversion Constructors
A constructor that can be called with a single argument is used for conversions from the type of the argument to the class type. Such a constructor is called a conversion constructor.
Sometimes a conversion is required but no conversion constructor exists in the class. These conversions cannot be performed by constructors. The compiler does not look for intermediate types through which to perform the conversion. For example, suppose a conversion exists from type Point to type Rect and a conversion exists from type int to type Point. The compiler does not supply a conversion from type int to type Rect by constructing an intermediate object of type Point.
Explicit Type Conversion Operator: ()
C++ allows explicit type conversion using a syntax similar to the function-call syntax.
simple-type-name ( expression-list )
A simple-type-name followed by an expression-list enclosed in parentheses constructs an object of the specified type using the specified expressions. The following example shows an explicit type conversion to type int:
int i = int( d );
需要特別注意的是,顯示類型轉換操作符只限於簡單類型的轉換,用戶自定義類型以前是不可以的,但是從C++11開始,也可以了。顯示類型轉換符的意義是不允許隱式類型轉換的情況下調用該類型轉換函數
#include < string>
using namespace std;
struct A
{
// implicit conversion to int
operator int() { return 100; }
// explicit conversion to std::string
explicit operator std:: string()
{
cout<< " to string "<<endl;
return " explicit ";
}
};
int main()
{
A a;
int i = a; // ok - implicit conversion
std:: string s1 = a; // error - requires explicit conversion
std:: string s2 = static_cast<std:: string>(a);
}