簡單總結(jié)一下C++中指針的用法,以后再寫一篇詳細(xì)的,關(guān)于smart pointer的總結(jié)。
指針的定義很簡單。在變量前打個(gè)星。例如一個(gè)class的名字叫A,那么指針定義為
A *pa;
有意點(diǎn)點(diǎn)另人混淆的是指針和const的混用。
char chr[] = "abc";
const char *p = chr; //這里p不是常數(shù)指針,而是把指針指向的地址定義為了常數(shù)。無論chr本身是不是指向常數(shù)內(nèi)存區(qū),但只要用p去操作,那么就不可以通過p去修改其內(nèi)容。
chr[2] = ’e’; // ok
p[2] = ’d’; // error
p+=1; // ok, 改的是p指向的地址而不是p的內(nèi)容。
真正的常數(shù)指針這么寫
char *const cp = s;
這時(shí)在常數(shù)內(nèi)存中allocate了一個(gè)指針的控件存儲(chǔ)cp,cp,也就是這個(gè)地址不能改,而其指向的內(nèi)存的值可以修改。
chr[2] = ’w’; //ok
cp[2] = ’y’; // ok
cp+=1; // error
char* 可以被轉(zhuǎn)換成const char*,因?yàn)椴僮骱鬀]有負(fù)面影響。反過來const char* 不能轉(zhuǎn)換成char*,如果可以的話會(huì)把本部可寫的內(nèi)存的數(shù)據(jù)改掉。
// good example
char chr[] = "abc";
char *p = chr;
const char *cp = p;
// bad example
char chr[] = "abc";
const char *p = chr;
char *p = cp; // error.
這種轉(zhuǎn)換常用在函數(shù)調(diào)用上,例如strcpy(char* source, char*dest)。這個(gè)操作只是想修改source,dest只是用于參考。為了避免函數(shù)修改dest可以把函數(shù)定義成strcpy(char* source, const char* dest)。
基本定義就這些了。對于指針的cast,C++作得比C更安全。例如有兩個(gè)完全不相干的class A和B。
B b;
A *p1,*p2;
p1 = (A *)(&b); // 這是C式的cast,不管A和B有什么關(guān)系,強(qiáng)型轉(zhuǎn)換。后果不堪設(shè)想。
C++中引入了static_cast操作,在一定程度上保護(hù)了操作的安全性,static_cast檢查操作數(shù)與要操作的類型是否匹配,匹配是有class繼承關(guān)系,無論誰繼承誰都可以。如果這個(gè)關(guān)系不存在,出編譯錯(cuò)誤。
p2 = static_cast(&b); //error。
但是這個(gè)檢查是不完全的,
class C : public A {}
C* pc = static_cast(p1); // ok. 因?yàn)閜c,p2歐繼承關(guān)系。
C++引入了RTTI得概念(Run Time Type Info)。通過dynamic_cast操作,可以檢查操作數(shù)的內(nèi)容,以確認(rèn)這個(gè)操作是否成功。檢查內(nèi)容的方法就是把相關(guān)類型的繼承關(guān)系和vtable都查一下。
p2 = dynamic_cast(p1);
在VC下使用dynamic_cast別忘了在當(dāng)前Project-->Setting下選Enable Run Time Type Info。如果忘了選這個(gè),debug模式下編譯會(huì)不通過,release模式下會(huì)編譯通過,運(yùn)行時(shí)Crash。
dynamic_cast比較復(fù)雜,另外Visual C++各不同版本的表現(xiàn)不一樣,這里詳細(xì)說一下我學(xué)到的和試出來的。一般書上說是三種不同情況,考慮到Visual C++版本的問題,我分五個(gè)情況討論。
1。upcast。從派生類向基類的轉(zhuǎn)換,只要基類的繼承關(guān)系是的,就會(huì)成功,如果不會(huì)有warning:"dynamic_cast used to convert to inaccessible or ambiguous base;"
下下面的例子中
class A{public: virtual void a(){}};
class B : public A {};
class C : public B {};
class D : public B {};
class E : public C, public D {};
int main()
{
E e, *pe = &e;
C *pc = dynamic_cast(pe);
B *pb = dynamic_cast(pe);
return 0;
}
轉(zhuǎn)換pb一行會(huì)有warning,而且得到NULL指針。
其繼承關(guān)系如下
A
/ \
B B
| |
C D
\ /
E
E到C成功,E到B失敗因?yàn)椴恢涝趺崔D(zhuǎn)換。同樣E到A也會(huì)失敗。注意這里的檢查只是指針類型pe的檢查,沒有查pe指向的object。把pe改成*pe = (E*)(new D());的話pe到pc的cast還會(huì)成功,不過pe到pb的cast會(huì)出現(xiàn)crash。這和dynamic_cast的實(shí)現(xiàn)有關(guān),這個(gè)exception不是bad_cast,所以用try{} chatch(...)接著以防不測
指針的定義很簡單。在變量前打個(gè)星。例如一個(gè)class的名字叫A,那么指針定義為
A *pa;
有意點(diǎn)點(diǎn)另人混淆的是指針和const的混用。
char chr[] = "abc";
const char *p = chr; //這里p不是常數(shù)指針,而是把指針指向的地址定義為了常數(shù)。無論chr本身是不是指向常數(shù)內(nèi)存區(qū),但只要用p去操作,那么就不可以通過p去修改其內(nèi)容。
chr[2] = ’e’; // ok
p[2] = ’d’; // error
p+=1; // ok, 改的是p指向的地址而不是p的內(nèi)容。
真正的常數(shù)指針這么寫
char *const cp = s;
這時(shí)在常數(shù)內(nèi)存中allocate了一個(gè)指針的控件存儲(chǔ)cp,cp,也就是這個(gè)地址不能改,而其指向的內(nèi)存的值可以修改。
chr[2] = ’w’; //ok
cp[2] = ’y’; // ok
cp+=1; // error
char* 可以被轉(zhuǎn)換成const char*,因?yàn)椴僮骱鬀]有負(fù)面影響。反過來const char* 不能轉(zhuǎn)換成char*,如果可以的話會(huì)把本部可寫的內(nèi)存的數(shù)據(jù)改掉。
// good example
char chr[] = "abc";
char *p = chr;
const char *cp = p;
// bad example
char chr[] = "abc";
const char *p = chr;
char *p = cp; // error.
這種轉(zhuǎn)換常用在函數(shù)調(diào)用上,例如strcpy(char* source, char*dest)。這個(gè)操作只是想修改source,dest只是用于參考。為了避免函數(shù)修改dest可以把函數(shù)定義成strcpy(char* source, const char* dest)。
基本定義就這些了。對于指針的cast,C++作得比C更安全。例如有兩個(gè)完全不相干的class A和B。
B b;
A *p1,*p2;
p1 = (A *)(&b); // 這是C式的cast,不管A和B有什么關(guān)系,強(qiáng)型轉(zhuǎn)換。后果不堪設(shè)想。
C++中引入了static_cast操作,在一定程度上保護(hù)了操作的安全性,static_cast檢查操作數(shù)與要操作的類型是否匹配,匹配是有class繼承關(guān)系,無論誰繼承誰都可以。如果這個(gè)關(guān)系不存在,出編譯錯(cuò)誤。
p2 = static_cast(&b); //error。
但是這個(gè)檢查是不完全的,
class C : public A {}
C* pc = static_cast(p1); // ok. 因?yàn)閜c,p2歐繼承關(guān)系。
C++引入了RTTI得概念(Run Time Type Info)。通過dynamic_cast操作,可以檢查操作數(shù)的內(nèi)容,以確認(rèn)這個(gè)操作是否成功。檢查內(nèi)容的方法就是把相關(guān)類型的繼承關(guān)系和vtable都查一下。
p2 = dynamic_cast(p1);
在VC下使用dynamic_cast別忘了在當(dāng)前Project-->Setting下選Enable Run Time Type Info。如果忘了選這個(gè),debug模式下編譯會(huì)不通過,release模式下會(huì)編譯通過,運(yùn)行時(shí)Crash。
dynamic_cast比較復(fù)雜,另外Visual C++各不同版本的表現(xiàn)不一樣,這里詳細(xì)說一下我學(xué)到的和試出來的。一般書上說是三種不同情況,考慮到Visual C++版本的問題,我分五個(gè)情況討論。
1。upcast。從派生類向基類的轉(zhuǎn)換,只要基類的繼承關(guān)系是的,就會(huì)成功,如果不會(huì)有warning:"dynamic_cast used to convert to inaccessible or ambiguous base;"
下下面的例子中
class A{public: virtual void a(){}};
class B : public A {};
class C : public B {};
class D : public B {};
class E : public C, public D {};
int main()
{
E e, *pe = &e;
C *pc = dynamic_cast(pe);
B *pb = dynamic_cast(pe);
return 0;
}
轉(zhuǎn)換pb一行會(huì)有warning,而且得到NULL指針。
其繼承關(guān)系如下
A
/ \
B B
| |
C D
\ /
E
E到C成功,E到B失敗因?yàn)椴恢涝趺崔D(zhuǎn)換。同樣E到A也會(huì)失敗。注意這里的檢查只是指針類型pe的檢查,沒有查pe指向的object。把pe改成*pe = (E*)(new D());的話pe到pc的cast還會(huì)成功,不過pe到pb的cast會(huì)出現(xiàn)crash。這和dynamic_cast的實(shí)現(xiàn)有關(guān),這個(gè)exception不是bad_cast,所以用try{} chatch(...)接著以防不測