日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STL4-类型转换

發(fā)布時間:2025/3/15 编程问答 9 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STL4-类型转换 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

#include<iostream> using namespace std;class Building{}; class Animal{}; class Cat :public Animal {}; //Cat是Animal的子類//static_cast //用于內置的數據類型及具有繼承關系的指針或者引用 void test01() {int a = 97;//static_cast<要轉換的類型>(轉換的數據)char c = static_cast<char>(a);cout << c << endl;//基礎數據類型指針 錯誤/*int* p = NULL;char* sp = static_cast<char*>(p);*///對象指針 錯誤/*Building* building = NULL;Animal* animal = static_cast<Animal*>(building);*///具有繼承關系的對象指針//父類指針轉換為子類指針Animal* animal = NULL;Cat* cat = static_cast<Cat*>(animal);//子類指針轉換為父類指針Cat* soncat = NULL;Animal* animal_father = static_cast<Animal*>(soncat);//父類引用zhuan子類引用Animal aniobj;Animal& aniref = aniobj;Cat& cat2 = static_cast<Cat&>(aniref);//子類引用轉父類引用Cat catobj;Cat& catref = catobj;Animal& anifather2 = static_cast<Animal&>(catref); }//dynamic_cast //只能轉換具有繼承關系的指針或者引用,在轉換前會進行對象類型的檢測(安全轉換) //只能由子類型轉換為父類型 void test02() {//基礎數據類型 錯誤//int a = 97;/*char c = dynamic_cast<char>(a);*///基礎數據類型指針 錯誤/*int* p = NULL;char* sp = dynamic_cast<char*>(p);*///非繼承關系的指針 錯誤/*Animal* animal = NULL;Building* building = dynamic_cast<Building*>(animal);*///具有繼承關系的指針//父類指針轉為子類指針 錯誤//子類轉換為父類是安全(從大到小) 父類轉換為子類是不安全的(從小到大)/*Animal* ani = NULL; Cat * cat = dynamic_cast<Cat*>(ani); 原因在于dynamic_cast自動做類型安全檢測*///子類指針轉換為父類指針Cat* cat1 = NULL;Animal* ani = dynamic_cast<Animal*>(cat1); }//const_cast 取消或者添加變量的const屬性后賦值給新值 //針對指針,引用,對象指針 void test03() {//基礎數據類型int a = 10;const int &b = a; //引用 別名//b=20; //錯誤 int& c = const_cast<int&>(b);c = 20;cout << "a:" << a << endl;cout << "b:" << b << endl;cout << "c:" << c << endl;//指針const int *p = NULL;int* p2=const_cast<int*>(p);int* p3 = NULL;const int* p4 = const_cast<const int*>(p3); }//reinterpret_cast 強制類型轉換 //只轉換指針 //任何類型指針都可以轉換為其他類型指針(包括函數指針) typedef void(*FUNC1)(int, int);//申明一個指針變量FUNC1,指向int(*)(int, int) void add(int a, int b) {cout << a + b << endl; } typedef int(*FUNC2)(int, char*);void test04() {//1、無關的指針類型都可以進行轉換Building* building = NULL;Animal* ani = reinterpret_cast<Animal*>(building);//2.函數指針轉換FUNC1 func1=add;//若不用typedef,可以直接func = add (此時,func就是變量,而非變量別名)func1(1, 2);FUNC2 func2 = reinterpret_cast<FUNC2>(func1); }int main(void) {test01();test02();test03();test04();system("pause");return 0; }

運行結果:

二、關于typedef void(*FUNC1)(int, int)的理解

#include "iostream"

using namespace std;

int add(int a,int b){
return (a+b);
}

typedef int (* func)(int ,int ) ;

void main(){
func f = add;
int n = f(1,2);
cout << n << endl;
}

在這里的意思是定義一種指針類型func,它是一種指向函數int (int,int)的指針,也就是說func表示的是這種類型的函數的地址,因為:

函數名不是其類型的一部分,函數的類型只由它的返回值和參數表決定.指向add()的指針必須指向與add()相同類型的函數帶有相同的返回類型和相同的參數表?? 。

int (* func)(int ,int )和int* func(int ,int )是不同的,后者說明的是返回一個int類型的指針,所以括號是必須加的

 typedef為C語言的關鍵字,作用是為一種數據類型定義一個新名字。這里的數據類型包括內部數據類型(int,char等)和自定義的數據類型(struct等)。

在編程中使用typedef目的一般有兩個

? ? ? ? 1、一個是給變量一個易記且意義明確的新名字

? ? ? ? 2、另一個是簡化一些比較復雜的類型聲明。

用typedef只是對已經存在的類型增加一個類型名,而沒有創(chuàng)造一個新的類型。只是增加了一個新名字,可以用該名字定義變量

二.用法

(1)用typedef聲明一個新類型名來代替已有的類型名。如:

typedef int Status //指定標識符Status代表int類型 typedef double DATE //指定標識符DATE代表double類型

這樣下面代碼等價:

int i; double j; Status i;DATE j;

(2)用typedef對數組類型起新名:

typedef int NUM[100];//聲明NUM為整數數組類型,可以包含100個元素 NUM n;//定義n為包含100個整數元素的數組,n就是數組名

(3)對一個結構體類型聲明一個新名字:

typedef struct //在struct之前用了關鍵字typedef,表示是聲明新類型名 {int month;int day;int year; } TIME; //TIME是新類型名,但不是新類型,也不是結構體變量名

?新聲明的新類型名TIME代表上面指定的一個結構體類型,這樣就可以用TIME定義該結構體變量,如:

TIME birthday; TIME *P //p是指向該結構體類型數據的指針

?

在typdef可以定義更加復雜的類型,這種情況遇到的不是很多,有時候多層的嵌套會將代碼演變的異常復雜,可讀性變差。雖然不推薦這么寫,但是對于他人寫的代碼要能理解。關于復雜定義的方式可以閱讀參考文獻6中的描述:

理解復雜聲明可用的“右左法則”:從變量名看起,先往右,再往左,碰到一個圓括號就調轉閱讀的方向;括號內分析完就跳出括號,還是按先右后左的順序,如此循環(huán),直到整個聲明分析完。舉例:
int (*func)(int *p)
首先找到變量名func,外面有一對圓括號,而且左邊是一個*號,這說明func是一個指針;然后跳出這個圓括號,先看右邊,又遇到圓括號,這說明(*func)是一個函數,所以func是一個指向這類函數的指針,即函數指針,這類函數具有int*類型的形參,返回值類型是int。
int (*func[5])(int *)
func右邊是一個[]運算符,說明func是具有5個元素的數組;func的左邊有一個*,說明func的元素是指針(注意這里的*不是修飾func,而是修飾func[5]的,原因是[]運算符優(yōu)先級比*高,func先跟[]結合)。跳出這個括號,看右邊,又遇到圓括號,說明func數組的元素是函數類型的指針,它指向的函數具有int*類型的形參,返回值類型為int。
?

?2. 隱藏技能

typedef 定義的新類型, 使用時可以省略括號.

?

typedef int NUM; NUM a = 10; // 也可寫成`NUM(a) = 10; NUM(b) = 12; // 也可寫成`NUM b = 12;

整形:?

typedef int x; // 定義了一個名為x的int類型

結構體:

typedef struct { char c; } s; // 定義名為s的struct類型

指針

typedef int *p; //定義了一個名為p的指針類型, 它指向int (中文描述指針好累)


接下來是高級的(注意標識符不一定在最后):
數組

typedef int A[]; // 定義一個名為A的ints數組的類型

函數:

typedef int f(); // 定義一個名為f, 參數為空, 返回值為int的函數類型 typedef int g(int); // 定義一個名為g, 含一個int參數, 返回值為int行的函數類型 typedef int P(); static P(Q);

應該就比較好理解了, P是一個新定義的function類型, 它返回值為int, 無參數
根據我的第2點說明, P(Q); 實際上等價于P Q, 聲明Q是一個返回值為int, 無參數的函數.

?

這玩意有什么用呢?
我們都知道C++語言里, 函數都是先聲明后使用的(除非在使用之前定義), 看以下例子:

#include <iostream> #include <stdio.h> #include <string> typedef int P(); // 簡單的 typedef void Q(int *p, const std::string& s1, const std::string& s2, size_t size, bool is_true); // 復雜的 class X { public:P(eat_shit); // 等價于聲明`int eat_shit();`Q(bullshit); // 等價于聲明`void bullshit(int *p, const string& s1, const string& s2, size_t size, bool is_true);` };int main() {X *xx;printf("shit ret: %d\n", xx->eat_shit());int a[] = {1, 3, 4, 5, 7};xx->bullshit(a, "foo", "bar", sizeof(a)/sizeof(int), true); } int X::eat_shit() {return 888; }void X::bullshit(int *p, const std::string& s1, const std::string& s2, size_t size, bool is_true) {std::cout << "s1: " << s1 << ", s2: " << s2 << ", size: " << size << std::endl;printf("elems:\n");for(int i = 0; i < size; i++) {printf("%d %s", *p++, (i == size-1) ? "" : ",");}printf("\n"); }

在閱讀Linux的內核代碼是經常會遇到一些復雜的聲明和定義,例如:

??????? (1)? void * (* (*fp1) (int)) [10];

??????? (2)? float (* (*fp2) (int, int, float)) (int);

??????? (3)? typedef double (* (* (*fp3) ()) [10]) ();

?????????????? fp3 a;

??????? (4)? int (* (*fp4()) [10]) ();

??????? 剛看到這些聲明或者定義時,一些初學者甚至有一定經驗的工程師都有可能頭皮發(fā)毛,基于大惑不解。如果缺乏經驗和方法來對這些內容進行理解,勢必會讓我們浪費大量的時間。

??????? 我嘗試對這些內容進行疏理和總結,為自己和有同樣困惑的同學答疑解惑。要理解這些復雜的聲明和定義,我覺得首先不能著急,應該由淺而深,逐步突破。下面先看一些簡單的定義:

??????? 1. 定義一個整型數

??????????? int a;

??????? 2. 定義一個指向整型數的指針

??????????? int *p;

??????? 3. 定義一個指向指針的指針,它指向的指針指向一個整型數

??????????? int **pp;

??????? 到這一步我想大多數人都還好理解,我們可以用一些簡單的代碼把這三條給串起來:

在閱讀Linux的內核代碼是經常會遇到一些復雜的聲明和定義,例如:

??????? (1)? void * (* (*fp1) (int)) [10];

??????? (2)? float (* (*fp2) (int, int, float)) (int);

??????? (3)? typedef double (* (* (*fp3) ()) [10]) ();

?????????????? fp3 a;

??????? (4)? int (* (*fp4()) [10]) ();

??????? 剛看到這些聲明或者定義時,一些初學者甚至有一定經驗的工程師都有可能頭皮發(fā)毛,基于大惑不解。如果缺乏經驗和方法來對這些內容進行理解,勢必會讓我們浪費大量的時間。

??????? 我嘗試對這些內容進行疏理和總結,為自己和有同樣困惑的同學答疑解惑。要理解這些復雜的聲明和定義,我覺得首先不能著急,應該由淺而深,逐步突破。下面先看一些簡單的定義:

??????? 1. 定義一個整型數

??????????? int a;

??????? 2. 定義一個指向整型數的指針

??????????? int *p;

??????? 3. 定義一個指向指針的指針,它指向的指針指向一個整型數

??????????? int **pp;

??????? 到這一步我想大多數人都還好理解,我們可以用一些簡單的代碼把這三條給串起來:

在閱讀Linux的內核代碼是經常會遇到一些復雜的聲明和定義,例如:

??????? (1)? void * (* (*fp1) (int)) [10];

??????? (2)? float (* (*fp2) (int, int, float)) (int);

??????? (3)? typedef double (* (* (*fp3) ()) [10]) ();

?????????????? fp3 a;

??????? (4)? int (* (*fp4()) [10]) ();

??????? 剛看到這些聲明或者定義時,一些初學者甚至有一定經驗的工程師都有可能頭皮發(fā)毛,基于大惑不解。如果缺乏經驗和方法來對這些內容進行理解,勢必會讓我們浪費大量的時間。

??????? 我嘗試對這些內容進行疏理和總結,為自己和有同樣困惑的同學答疑解惑。要理解這些復雜的聲明和定義,我覺得首先不能著急,應該由淺而深,逐步突破。下面先看一些簡單的定義:

? 1. 定義一個整型數

??????????? int a;

?? 2. 定義一個指向整型數的指針

??????????? int *p;

?? 3. 定義一個指向指針的指針,它指向的指針指向一個整型數

??????????? int **pp;

??????? 到這一步我想大多數人都還好理解,我們可以用一些簡單的代碼把這三條給串起來:

int a; int *p; int **pp; p = &a; // p指向整數a所在的地址 pp = &p; // pp指向指針p

4. 定義一個包含10個整型數的數組

??????????? int arr[10];

?5. 定義一個指向包含10個整型數數組的指針

??????????? int (*pArr) [10];

??????? 用幾行代碼將4、5兩個定義串起來:

int arr[10]; int (*pArr) [10];pArr = &arr;

6. 定義一個指向函數的指針,被指向的函數有一個整型參數并返回整型值

?

???????????? int (*pfunc) (int);

?7. 定義一個包含10個指針的數組,其中包含的指針指向函數,這些函數有一個整型參數并返回整型值

???????????? int (*arr[10]) (int);

?

??????? 用幾行代碼將6、7兩個定義串起來:

int (*pfunc) (int); int (*arr[10]) (int);arr[0] = pfunc;

到這一步,似乎就不是那么好理解了。現(xiàn)在需要請出用于理解復雜定義的“右左法則”:

?

??????? 從變量名看起,先往右,再往左,碰到圓括號就調轉閱讀的方向;括號內分析完就跳出括號,還是先右后左的順序。如此循環(huán),直到分析完整個定義。

??????? 讓我們用這個方法來分析上面的第6條定義:int (*pfunc) (int);

??????? 找到變量名pfunc,先往右是圓括號,調轉方向,左邊是一個*號,這說明pfunc是一個指針;然后跳出這個圓括號,先看右邊,又遇到圓括號,這說明(*pfunc)是一個函數,所以pfunc是一個指向這類函數的指針,即函數指針,這類函數具有一個int類型的參數,返回值類型是int。

??????? 接著分析第7條定義:int (*arr[10]) (int);

??????? 找到變量名arr,先往右是[]運算符,說明arr是一個數組;再往左是一個*號,說明arr數組的元素是指針(注意:這里的*修飾的不是arr,而是arr[10]。原因是[]運算符的優(yōu)先級比*要高,arr先與[]結合。);跳出圓括號,先往右又遇到圓括號,說明arr數組的元素是指向函數的指針,它指向的函數有一個int類型的參數,返回值類型是int。

??????? 分析完這兩個定義,相信多數人心里面應該有點譜了。可應該還有人會問:怎么判斷定義的是函數指針(定義6),還是數組指針(定義5),或是數組(定義7)?可以抽象出幾個模式:

  • type (*var)(...); // 變量名var與*結合,被圓括號括起來,右邊是參數列表。表明這是函數指針
  • type (*var)[];? ? //變量名var與*結合,被圓括號括起來,右邊是[]運算符。表示這是數組指針
  • type (*var[])...; ? ? // 變量名var先與[]結合,說明這是一個數組(至于數組包含的是什么,由旁邊的修飾決定) ??

??????? 至此,我們應該有能力分析文章開始列出來了幾條聲明和定義:

??????? (1)? void * (* (*fp1) (int)) [10];

??????? 找到變量名fp1,往右看是圓括號,調轉方向往左看到*號,說明fp1是一個指針;跳出內層圓括號,往右看是參數列表,說明fp1是一個函數指針,接著往左看是*號,說明指向的函數返回值是指針;再跳出外層圓括號,往右看是[]運算符,說明函數返回的是一個數組指針,往左看是void *,說明數組包含的類型是void *。簡言之,fp1是一個指向函數的指針,該函數接受一個整型參數并返回一個指向含有10個void指針數組的指針。

??????? (2) float (* (*fp2) (int, int, float)) (int);

??????? 找到變量名fp2,往右看是圓括號,調轉方向往左看到*號,說明fp2是一個指針;跳出內層圓括號,往右看是參數列表,說明fp2是一個函數指針,接著往左看是*號,說明指向的函數返回值是指針;再跳出外層圓括號,往右看還是參數列表,說明返回的指針是一個函數指針,該函數有一個int類型的參數,返回值類型是float。簡言之,fp2是一個指向函數的指針,該函數接受三個參數(int, int和float),且返回一個指向函數的指針,該函數接受一個整型參數并返回一個float。

?

??????? (3)? typedef double (* (* (*fp3) ()) [10]) ();

?????????????? fp3 a;

??????? 如果創(chuàng)建許多復雜的定義,可以使用typedef。這一條顯示typedef是如何縮短復雜的定義的。

??????? 跟前面一樣,先找到變量名fp3(這里fp3其實是新類型名),往右看是圓括號,調轉方向往左是*,說明fp3是一個指針;跳出圓括號,往右看是空參數列表,說明fp3是一個函數指針,接著往左是*號,說明該函數的返回值是一個指針;跳出第二層圓括號,往右是[]運算符,說明函數的返回值是一個數組指針,接著往左是*號,說明數組中包含的是指針;跳出第三層圓括號,往右是參數列表,說明數組中包含的是函數指針,這些函數沒有參數,返回值類型是double。簡言之,fp3是一個指向函數的指針,該函數無參數,且返回一個含有10個指向函數指針的數組的指針,這些函數不接受參數且返回double值。

??????? 這二行接著說明:a是fp3類型中的一個。

??????? (4)? int (* (*fp4()) [10]) ();

??????? 這里fp4不是變量定義,而是一個函數聲明。

??????? 找到變量名fp4,往右是一個無參參數列表,說明fp4是一個函數,接著往左是*號,說明函數返回值是一個指針;跳出里層圓括號,往右是[]運算符,說明fp4的函數返回值是一個指向數組的指針,往左是*號,說明數組中包含的元素是指針;跳出外層圓括號,往右是一個無參參數列表,說明數組中包含的元素是函數指針,這些函數沒有參數,返回值的類型是int。簡言之,fp4是一個返回指針的函數,該指針指向含有10個函數指針的數組,這些函數不接受參數且返回整型值。

  • 用typedef簡化復雜的聲明和定義

??????? 以上我們已經看到了不少復雜的聲明和定義,這里再舉一個例子:

??????? int *(*a[10]) (int, char*);

??????? 用前面的“右左法則”,我們可以很快弄清楚:a是一個包含10個函數指針的數組,這些函數的參數列表是(int, char*),返回值類型是int*。理解已經不成問題,這里的關鍵是如果要定義相同類型的變量b,都得重復書寫:

??????? int *(*b[10]) (int, char*);

??????? 這里有沒有方便的辦法避免這樣沒有價值的重復?答案就是用typedef來簡化復雜的聲明和定義。

??????? typedef可以給現(xiàn)有的類型起個別名。這里用typedef給以上a、b的類型起個別名:?

typedef int *(*A[10]) (int, char*); // 在之前定義的前面加入typedef,然后將變量名a替換成類型名A

現(xiàn)在要再定義相同類型的變量c,只需要:

??????? A c;

?

??????? 再看一例:

??????? void (*b[10]) (void (*)());

??????? 先替換右邊括號里面的參數,將void (*)()的類型起個別名pParam:???????

typedef void (*pParam) ();

再替換左邊的變量b,為b的類型起個別名B:

typedef void (*B) (pParam);

原聲明的簡化版:

B b[10]; #include<stdio.h> int inc(int a) {return(++a); }int multi(int*a, int*b, int*c) {return(*c = *a**b); }typedef int(FUNC1)(int); //申明一個指針變量FUNC1,指向int(int) typedef int(FUNC2)(int*, int*, int*);void show(FUNC2 fun, int arg1, int *arg2) {//fun 為指向函數int multi(int*a,int*b,int*c)的指針//arg1 = 10,arg2 =&a;FUNC1 *p = &inc; //p為指向函數inc的指針int temp = p(arg1); //等價于 temp = inc(arg1) = inc(10) = 11fun(&temp, &arg1, arg2);//運行fun()函數后,*arg2 = temp * arg1 = 11 * 10 = 110printf("%d\n", *arg2); } int main() {int a;show(multi, 10, &a);return 0; }

結果為110

參考自https://blog.csdn.net/hai008007/article/details/80651886

https://blog.csdn.net/baoendemao/article/details/41209697

?

?

?

?

?

總結

以上是生活随笔為你收集整理的STL4-类型转换的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。