文章目錄
- 前言
- 類型轉換的細節
- 1. 類型轉換的臨時變量
- 細節二:const與指針
前言
關于類型轉換的細節,這里小編和大家探討兩個方面:
- 關于類型轉化的臨時變量的問題
const
關鍵字的權限問題 — 即修改權限。小編或通過一道例題(配圖)來帶大家了解這個權限問題!
類型轉換的細節
還有一些常見的問題(例如整型提升的問題)小編這里不做介紹,主要介紹下面兩種:
1. 類型轉換的臨時變量
為什么說類型轉換的細節呢?來看下面的程序:
#include<iostram>
using namespace std;
int main()
{int a = 0;double& ref = a;return 0;
}
又或者是這樣:
#include<iostram>
using namespace std;
int main()
{int a = 0;double& ref = (double)a;return 0;
}
上面代碼有問題嗎?當然有問題,VS2022編譯器是會報錯的……
這是什么原因導致的呢?
- 實際上一個類型轉換的過程應該是這樣的:
臨時變量tmp
是具有常性的(可讀不可寫),所以是無法如此被引用的。所以只能通過另外的方法,得到它們的引用。
注:關于這個觀點證明,借助右值引用的移動語義就可以完成驗證。
#include<iostram>
using namespace std;
int main()
{int a = 0;const double& ref = a;return 0;
}
- 一定是
const type&
才可以。一定要注意這個細節。 - 關于對于這個問題,編譯器在對自定義類型的時候都會做出一定的優化。
那么對于這些場景就會產生許多問題,例:
namespace test
{class A{public:A():_a(1){}virtual void set(int val){_a = val;}int _a;};class B :public A{public:B():_b(0){}virtual void set(int val){static_cast<A>(*this).set(val); //很有問題的寫法//A::set(val);}int _b;};void Test1(){B bb;bb.set(120);cout << bb._a << endl;}
}
我們想要在B
類的set
中調用A
類(父類)的set
,但是這樣的類型轉換是不會起到任何效果的,還記得剛剛所討論的嗎?類型轉換會產生臨時變量,臨時變量是不會改變原來的值的。這些都是隱式類型轉換的細節。
包括有時候對指針進行了強制類型轉換過后:
int a = 10;
int* ptr = &a;
char* c = ++(char*)ptr;
這樣的類型轉換都是不會達到如愿的結果的!!!
細節二:const與指針
在說明這個問題之前,我們先聲明:
- 權限可以縮小
- 權限可以平移
- 權限不能放大
來看下面這個例子,來理解一些關于權限問題
const int* const ptr1 = 0;
const int* ptr2 = 1;
int* const ptr3 = 2;
對于上面三個語句,以我們對于const
的理解:
ptr1
和ptr1
指向的內容都不可以更改ptr2
指向的內容不可以更改ptr3
本身不能更改
我們都知道:const T*
是不允許轉換為T*
的。(除非使用const_cast
去掉const
屬性)這些都是我們所了解的,那么如果加上二級指針呢?
例如下面代碼:
const int d = 0;
const int* c = &d; //1
int e = 1;
int *f = &e; //2
int **b = &f; //3
const int **a = b; //4
*a = c; //5
對于上面所標識的5條語句,你覺得有沒有錯誤的呢?
編譯器會告訴你,語句4是錯誤的!!
這個時候就要問為什么?
我們來分析一下:
-
首先我們來看,這個賦值的過程,來看是否有權限的放大問題。首先,創建一個
const
變量d
,然后一個創建了一個const int*
的指針指向這個變量,沒有問題,是一個權限的平移。然后略過創建e,f,b
過程,來到const int **a = b
語句,從權限來看,這似乎是沒有問題的,a
是一個指針的指針,對于a
指向的指針的指向內容是一個const
內容,而b
指針指向的指針的指向內容不是一個const
內容,似乎看來這是一個權限的縮小。指向是有潛在有問題的! -
我們用
b
初始化了a
,那么修改*a
,就是修改*b
,經過了語句5,此時*a
和*b
都指向了c
。發現了嗎?c
是一個const int*
類型,而b
是一個int*
類型。沒錯,這里發生了什么?間接地使const int*
類型轉換為了int*
類型(違背了上面的原則!)。即使是我們去掉了語句5,結果仍然不會通過!
-
下面我們作圖來解釋關系:
所以:int **
不能轉換為 const int **
!!!這是為了以絕后患。如果在const int **
聲明的時候做如下聲明:const int* const *a = b
那么語句*a = c
就不會通過編譯,就不會出現報錯的問題了!
那么有了以上的一些儲備,我們來看如下的代碼:
class A{};void f(const A** p){}
void g(const A* const *p){}
void k(const A*& p){}int main()
{const A* ca = new A;A* a = new A;A** p = &a;k(ca); // 1f(p); // 2g(p); // 3// ……return 0;
}
在這個代碼中,你能看出來語句1,2,3哪些有問題,為什么呢?
還有什么經驗細節,都歡迎大家分享!
完。