標識符
extern
置於變量或函數前,以表示變量或函數的定義在別的文件中,提示編譯器碰見此變量和函數時在其餘模塊中尋找其定義。在使用extern時候要嚴格對應聲明時的格式。 ios
在一個源文件裏定義了一個數組:char a[6];
在另一個文件裏用下列語句進行了聲明:extern char *a;
不能夠,程序運行時會告訴你非法訪問。緣由在於,指向類型T的指針
並不等價於類型T的數組
。extern char *a聲明的是一個指針
變量而不是字符數組
,所以與實際的定義不一樣,從而形成運行時非法訪問。應該將聲明改成extern char a[ ]。
現代編譯器通常採用按文件編譯的方式,所以在編譯時,各個文件中定義的全局變量是互相不透明的。也就是說,在編譯時,全局變量的可見域限制在文件內部。 程序員
extern 「C」
在C++環境下使用C函數的時候,經常會出現編譯器沒法找到obj模塊中的C函數定義,從而致使連接失敗的狀況,應該如何解決這種狀況呢?
答案與分析: 數組
C++語言在編譯的時候爲了解決函數的多態問題,會將函數名和參數聯合起來生成一箇中間的函數名稱,而C語言則不會,所以會形成連接時找不到對應函數狀況,此時C函數就須要用extern 「C」進行連接指定,這告訴編譯器,請保持個人名稱,不要給我生成用於連接的中間函數名。 函數
#pragma
預處理指令,設定編譯器的狀態或者是指示編譯器完成一些特定的動做。 spa
#pragma message(「消息文本」)
當 編譯器遇到這條指令時就在編譯輸出窗口中將消息文本打印出來。 指針
獲取結構體偏移量 code
這個宏定義在C標準庫的頭文件 stddef.h 裏有定義
typedef unsigned long size_t;
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#include <iostream>
using namespace std;
struct test
{
int a;
int b;
char c;
int d;
};
#define FIND(structTest,e) (size_t) &(((structTest*)0)->e)
int main()
{
size_t s = FIND(test,b);
//test t;
cout<<s<<endl;
char c;
cin>>c;
return 0;
}
四、隱式轉換 htm
第一種:classB: public A {…} 對象
B公有繼承A,能夠是間接公有繼承,當把B的對象賦值給A,會發生隱式轉換。 繼承
(待求證,保護繼承、私有繼承、B是A的成員可否發生轉換?)
第二種:
classB:{
OperatorA();
….
}
轉換constructor。類B實現了隱式轉化爲類A;compiler會在須要的時候自動調用該函數發生類型轉換,若是想要在代碼中顯式的調用轉換函數才能發生類型轉化,能夠定義explicit operator A()
第三種:
class A{
A (const B &)
}
A實現了一個個non-explicit的構造函數,參數爲B(還能夠帶其餘的有缺省值的參數)
第四種:A&operator =(const B & )
注意:對於類之間的公有繼承總能夠把子類轉化爲父類,只是把派生類對象切割爲基類對象便可。
注意2:上述第二種和第三種方法同時存在一個程序中,應該注意這樣的調用:
f(const A &);
B b;
f(b)則會產生調用的二義性。
注意3:若是不想使用隱式生成的函數(固然這些函數通常是缺省構造函數、copy構造函數和賦值構造函數),就要把它顯式的禁止;對於通常的轉換constructor能夠添加explicit明確的要求顯式的調用,compiler不能自動發生隱式轉換。如:
Private:
A &operator = (const B &);
A (const A & );
按照默認規定,只有一個參數的構造函數也定義了一個隱式轉換,將該構造函數對應數據類型的數據轉換爲該類對象,以下面所示:
class String {
String ( const char* p );
// 用C風格的字符串p做爲初始化值
//…
}
String s1 = 「hello」; //OK 隱式轉換,等價於String s1 = String(「hello」);
可是有的時候可能會不須要這種隱式轉換,以下:
class String {
String ( int n ); //本意是預先分配n個字節給字符串
String ( const char* p );
// 用C風格的字符串p做爲初始化值
//…
}
下面兩種寫法比較正常:
String s2 ( 10 ); //OK 分配10個字節的空字符串
String s3 = String ( 10 ); //OK 分配10個字節的空字符串
下面兩種寫法就比較疑惑了:
String s4 = 10; //編譯經過,也是分配10個字節的空字符串
String s5 = ‘a’; //編譯經過,分配int(‘a’)個字節的空字符串
s4 和s5 分別把一個int型和char型,隱式轉換成了分配若干字節的空字符串,容易使人誤解。
爲了不這種錯誤的發生,咱們能夠聲明顯示的轉換,使用
explicit 關鍵字:
class String {
explicit String ( int n ); //本意是預先分配n個字節給字符串
String ( const char* p );
// 用C風格的字符串p做爲初始化值
//…
}
加上
explicit
,就抑制了String ( int n )的隱式轉換,
下面兩種寫法仍然正確:
String s2 ( 10 ); //OK 分配10個字節的空字符串
String s3 = String ( 10 ); //OK 分配10個字節的空字符串
下面兩種寫法就不容許了:
String s4 = 10; //編譯不經過,不容許隱式的轉換
String s5 = ‘a’; //編譯不經過,不容許隱式的轉換
所以,某些時候,
explicit 能夠有效得防止構造函數的隱式轉換帶來的錯誤或者誤解
----------------------------------------------------------
explicit 只對構造函數起做用,用來抑制隱式轉換。如:
class A {
A(int a);
};
int Function(A a);
當調用 Function(2) 的時候,2 會隱式轉換爲 A 類型。這種狀況經常不是程序員想要的結果,因此,要避免之,就能夠這樣寫:
class A {
explicit A(int a);
};
int Function(A a);
這樣,當調用 Function(2) 的時候,編譯器會給出錯誤信息(除非 Function 有個以 int 爲參數的重載形式),這就避免了在程序員絕不知情的狀況下出現錯誤。
總結:explicit 只對構造函數起做用,用來抑制隱式轉換。