1. 程式人生 > >C++型別轉化表示式小結

C++型別轉化表示式小結

const_cast

根據http://www.cplusplus.com的說法,const_cast用於物件指標或引用的const的新增和刪除操作

例子如下:

// const_cast
#include <iostream>
using namespace std;

void print (char * str)
{
  cout << str << '\n';
}

int main () {
  const char * c = "sample text";
  print ( const_cast<char *> (c) );
  return
0; }

輸出為

sample text

函式指標和成員函式指標不可用於const_cast

const_cast可以使實際指代const物件的到非const型別的引用或指標,但是通過非const訪問路徑修改const物件則是未定義行為。

更詳細的例子

#include <iostream>

struct type {
    type() :i(3) {}
    void m1(int v) const {
        // this->i = v;                 // 編譯錯誤:這是指向 const 的指標
        const_cast
<type*>(this)->i = v; // 只要物件不是 const 就 OK } int i; }; int main() { int i = 3; // i 不宣告為 const const int& cref_i = i; const_cast<int&>(cref_i) = 4; // OK :修改 i std::cout << "i = " << i << '\n'; type t; // note, if this is const type t;, then t.m1(4); is UB
t.m1(4); std::cout << "type::i = " << t.i << '\n'; const int j = 3; // j 宣告為 const int* pj = const_cast<int*>(&j); // *pj = 4; // 未定義行為! void (type::*mfp)(int) const = &type::m1; // 指向成員函式指標 // const_cast<void(type::*)(int)>(mfp); // 編譯錯誤: const_cast 對函式指標不起作用 }

輸出

i = 4
type::i = 4

reinterpret_cast

reinterpret_cast可以在任意型別指標進行轉換,哪怕是不相關的型別。

還可用於指標或引用與整型的相互轉化,不單是int,還包括short、long等整數型別。

原因在於reinterpret_cast是“simple binary copy”,cplusplus的原話是“The operation result is a simple binary copy of the value from one pointer to the other. All pointer conversions are allowed: neither the content pointed nor the pointer type itself is checked.”

經過測試,整型與char *之間的轉化也可以正常進行

cppreference的例子

#include <cstdint>
#include <cassert>
#include <iostream>
int f() { return 42; }
int main()
{
    int i = 7;

    // 指標到整數並轉回
    uintptr_t v1 = reinterpret_cast<uintptr_t>(&i); // static_cast 為錯誤
    std::cout << "The value of &i is 0x" << std::hex << v1 << '\n';
    int* p1 = reinterpret_cast<int*>(v1);
    assert(p1 == &i);

    // 到另一函式指標並轉回
    void(*fp1)() = reinterpret_cast<void(*)()>(f);
    // fp1(); 未定義行為
    int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
    std::cout << std::dec << fp2() << '\n'; // 安全

    // 通過指標的類型別名使用
    char* p2 = reinterpret_cast<char*>(&i);
    if(p2[0] == '\x7')
        std::cout << "This system is little-endian\n";
    else
        std::cout << "This system is big-endian\n";

    // 通過引用的類型別名使用
    reinterpret_cast<unsigned int&>(i) = 42;
    std::cout << i << '\n';

    const int &const_iref = i;
    // int &iref = reinterpret_cast<int&>(const_iref); // 編譯錯誤——不能去除 const
    // 必須用 const_cast 代替: int &iref = const_cast<int&>(const_iref);
}

輸出

The value of &i is 0x7fff352c3580
42
This system is little-endian
42

static_cast

static_cast可以在有聯絡的型別之間進行指標轉換(between pointers to related classes),不但包括派生類轉換基類,也包括基類轉換派生類。

static_cast還可以完成以下兩種

Convert from void* to any pointer type.可以有void *到任何型別

Convert integers, floating-point values and enum types to enum types.由整數、浮點、列舉值到列舉值

此外

Explicitly call a single-argument constructor or a conversion operator. 呼叫單一引數的建構函式或轉換的過載符號

Convert to rvalue references. (由左值)轉化成右值的引用

Convert enum class values into integers or floating-point values. 列舉類轉化為整數、浮點數

Convert any type to void, evaluating and discarding the value. 任意型別到void,求值後捨棄該值

示例

#include <vector>
#include <iostream>

struct B {
    int m = 0;
    void hello() const {
        std::cout << "Hello world, this is B!\n";
    }
};
struct D : B {
    void hello() const {
        std::cout << "Hello world, this is D!\n";
    }
};

enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };

int main()
{
    // 1: 初始化轉換
    int n = static_cast<int>(3.14); 
    std::cout << "n = " << n << '\n';
    std::vector<int> v = static_cast<std::vector<int>>(10);
    std::cout << "v.size() = " << v.size() << '\n';

    // 2: 靜態向下轉型
    D d;
    B& br = d; // 通過隱式轉換向上轉型
    br.hello();
    D& another_d = static_cast<D&>(br); // 向下轉型
    another_d.hello();

    // 3: 左值到亡值
    std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
    std::cout << "after move, v.size() = " << v.size() << '\n';

    // 4: 棄值表示式
    static_cast<void>(v2.size());

    // 5. 隱式轉換的逆
    void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "*ni = " << *ni << '\n';

    // 6. 陣列到指標後隨向上轉型
    D a[10];
    B* dp = static_cast<B*>(a);

    // 7. 有作用域列舉到 int 或 float
    E e = E::ONE;
    int one = static_cast<int>(e);
    std::cout << one << '\n';

    // 8. int 到列舉,列舉到另一列舉
    E e2 = static_cast<E>(one);
    EU eu = static_cast<EU>(e2);

    // 9. 指向成員指標向上轉型
    int D::*pm = &D::m;
    std::cout << br.*static_cast<int B::*>(pm) << '\n';

    // 10. void* 到任何型別
    void* voidp = &e;
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}

輸出

n = 3
v.size() = 10
Hello world, this is B!
Hello world, this is D!
after move, v.size() = 0
*ni = 3
1
0

dynamic_cast

dynamic_cast只能用於類或者void *的指標、引用轉換,同時必須為多型以使用執行時檢查的

例子

#include <iostream>

struct V {
    virtual void f() {};  // 必須為多型以使用執行時檢查的 dynamic_cast
};
struct A : virtual V {};
struct B : virtual V {
  B(V* v, A* a) {
    // 構造中轉型(見後述 D 的建構函式中的呼叫)
    dynamic_cast<B*>(v); // 良好定義: v 有型別 V* , B 的 V 基類,產生 B*
    dynamic_cast<B*>(a); // 未定義行為: a 有型別 A* , A 非 B 的基類
  }
};
struct D : A, B {
    D() : B((A*)this, this) { }
};

struct Base {
    virtual ~Base() {}
};

struct Derived: Base {
    virtual void name() {}
};

int main()
{
    D d; // 最終匯出類
    A& a = d; // 向上轉型,可以用 dynamic_cast ,但不必須
    D& new_d = dynamic_cast<D&>(a); // 向下轉型
    B& new_b = dynamic_cast<B&>(a); // 側向轉型


    Base* b1 = new Base;
    if(Derived* d = dynamic_cast<Derived*>(b1))
    {
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // 呼叫安全
    }

    Base* b2 = new Derived;
    if(Derived* d = dynamic_cast<Derived*>(b2))
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // 呼叫安全
    }

    delete b1;
    delete b2;
}

輸出

downcast from b2 to d successful

dynamic_cast與static_cast在類轉換上的不同在於,dynamic_cast會確保轉化成功,在轉化不成功時會設定為NULL,如上例中

Derived* d = dynamic_cast<Derived*>(b1)

相關推薦

C++型別轉化表示式小結

const_cast 根據http://www.cplusplus.com的說法,const_cast用於物件指標或引用的const的新增和刪除操作 例子如下: // const_cast #include <iostream> using

C# bool型別轉化為字串首字母會大寫

C#中bool型別在轉化為字串型別時會自動大些首字母!!!!!!!!!......... 這樣:.. 怎麼解決呢。。 如果想在bool型別是 都轉化為小寫的 就這樣 一句搞定 bool b

C# Matlab資料型別轉化

注意:1,C#呼叫matlab生成的dll中的函式時,入口引數只能是MWArray型別(Matlab中的資料型別)或者MWNumericArray型別(Matlab和C#的中間型別)(通過MWNumericArray型別可以點出許多轉換函式) 2,可以將字面值直接賦給MWA

C#中將DataTable型別轉化為泛型集合

DataTable是什麼? DataTable 是一個臨時儲存資料的網格虛擬表(表示記憶體中資料的一個表。)。DataTable是ADO dot net庫中的核心物件。它可以被應用在 VB 和 ASP 上。它無須程式碼就可以簡單的繫結資料庫。它具有微軟風格的使用者介面。 注意!!! 當訪問DataTab

string, char*, int型別轉換 , c++強制轉化

一、C++程式碼 以下是常用的幾種型別互相之間的轉換 string 轉 int .............................. char* 轉 int #include <stdlib.h> int atoi(const char *nptr

Objective-C資料型別表示式

4.1資料型別和常量 Objective-C提供了4中基本的資料型別:int 、float、double、char 。 Objective-C中,任何數字,單個字元或者字串通常成為常量。 在程式碼清單4-1中使用了基本的Objective-C資料型別#import <

C++第四周學習小結

str 利用 strong 忘記 c++ 記得 頭文件 動手 獲取 本周小結: ①學會了簡單的輸入輸出 ②要記得加對應的頭文件,否則編譯會出錯 ③不能只拘泥於已學的知識,要學會自己尋找解決問題的辦法,自己動手獲取新知識,善於利用資源 下周計劃: 跟上老師的進度的同時要主動預

包裝類(Integer/Boolean等、字串與基本資料型別轉化,-127-128自動裝箱入池)

為什麼要有包裝類? Object類可以接收所有引用資料型別。然而在Java中,資料型別分為基本資料型別和引用資料型別,那麼基本資料型別如何處理呢? 使用包裝類 :包裝類是將基本資料型別封裝到類中,因為Object無法接受基本資料型別,封裝成類後就可以用Object類來接收。 簡單定義一個in

C# 正則表示式的一些語法筆記

基礎語法看這裡:正則表示式語法 下面是一些其他要注意的點…… 反斜槓 + 元字元 表示匹配元字元本身。 eg:元字元 . 表示除換行符以外的任意字元,而 \. 表示匹配 . 。 一般定義正則表示式字串時會加上 @,表示不轉義。 eg:string patt

C#正則表示式簡單總結

C#: c#中驗證正則表示式的類為System.Text.RegularExpressions.Regex 簡單的匹配方法為IsMatch(4個過載方法) 正則表示式語法: 一、匹配單個字元 [ ]:從中選擇一個字元匹配 如:單詞字元([ae])、非單詞

C# -- 正則表示式匹配字元之含義

原文: C# -- 正則表示式匹配字元之含義 C#正則表示式匹配字元之含義 1.正則表示式的作用:用來描述字串的特徵。 2.各個匹配字元的含義: .   :表示除\n以外的單個字元 [ ]  :表示在字元陣列[]中羅列出來的字元任意取單個 |   :表示“或”的意思

C# 正則表示式檢查輸入字元

public class Validator 2 { 3 #region 匹配方法 4 /// <summary> 5 /// 驗證字串是否匹配正則表示式描述的規則 6

js的顯性型別轉化toString()

js的顯性型別轉化toString(); toString()是方法需要被呼叫,直接轉化為字串型別 var a = 123; a.toString(); typeof(a); // 輸入字串"123",a的型別還是number型別 var a = 123; var b = a.

C語言高階篇 - 1.C語言複雜表示式和指標高階應用

1.指標陣列與陣列指標 1.1、字面意思來理解指標陣列與陣列指標 (1)指標陣列的實質是一個數組,這個陣列中儲存的內容全部是指標變數。 (2)陣列指標的實質是一個指標,這個指標指向的是一個數組。   1.2、分析指標陣列與陣列指標的表示式 (1)int *

Effective Modern C++:06lambda表示式

         lambda表示式實際上是語法糖,任何lambda表示式能做到的,手動都能做到,無非是多打幾個字。但是lambda作為一種建立函式物件的手段,實在太過方便,自從有了lambda表示式,使用複雜謂詞來呼叫STL中的

如何用C語言計算表示式的值,棧的經典應用

宣告:這個程式可以計算+,-,*,/,負數,小數 負數用括號括起來例如(-1) 負數的計算過程:(-1)  轉變為 (0-1)  哈哈~   分成六個點: 1.我的檔案結構 2.順序堆疊的標頭檔案 3.標頭

c++11 lambda 表示式

轉:https://www.cnblogs.com/ChinaHook/p/7658443.html 1、  定義   lambda表示式是C++11非常重要也是很常用的特性之一,來源於函數語言程式設計的概念,也是現代程式語言的一個特點。它有如下特點: 宣告式程式設計風格

C# 型別轉換

型別轉換從根本上說是型別鑄造,或者說是把資料從一種型別轉換為另一種型別。在 C# 中,型別鑄造有兩種形式: 隱式型別轉換 - 這些轉換是 C# 預設的以安全方式進行的轉換, 不會導致資料丟失。例如,從小的整數型別轉換為大的整數型別,從派生類轉換為基類。 顯式型別轉換 

C 正則表示式的完全匹配 部分匹配及忽略大小寫的問題

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

C++11 lambda表示式不能捕獲map/unordered_map值

先看一道面試題。 某公司中有N名員工,給定所有員工工資的清單,財務人員要按照持定的順序排列員工的工資,他按照工資的頻次降序排列,即給定清單中所有頻次較高的工資將在頻次較低的工資之前出現,如果相同數量的員工都有相同的工資,則將按照給定清單中該工資第一次出現的順序排列。 寫一演算法來幫助財務人員