1. 程式人生 > >using和typedef用法

using和typedef用法

可以使用別名宣告來宣告要使用的宣告型別的同義詞的名稱。 (此機制也稱為非正式類型別名)。 此外可以使用此機制來建立別名模板,可以是對自定義分配器特別有用。

語法

複製

using identifier = type;  

備註

identifier
別名的名稱。

type
您為其建立別名的型別識別符號。

別名未引入新型別,且無法更改現有型別名稱的含義。

別名的最簡單形式等效於C + + 03的typedef機制:

// C++11  
using counter = long;  

// C++03 equivalent:  
// typedef long counter;  

二者都支援建立較為簡單型別的變數。 對於 std::ios_base::fmtflags

 這樣的變數而言,別名也許會更有用:

// C++11  
using fmtfl = std::ios_base::fmtflags;  

// C++03 equivalent:  
// typedef std::ios_base::fmtflags fmtfl;  

fmtfl fl_orig = std::cout.flags();  
fmtfl fl_hex = (fl_orig & ~std::cout.basefield) | std::cout.showbase | std::cout.hex;  
// ...  
std::cout.flags(fl_hex);  

別名也使用函式指標,但比等效的 typedef 的可讀性要強得多:

// C++11  
using func = void(*)(int);  

// C++03 equivalent:  
// typedef void (*func)(int);  

// func can be assigned to a function pointer value  
void actual_function(int arg) { /* some code */ }  
func fptr = &actual_function;  

typedef的一個侷限性是它不能使用模板。 但是,C++11 中的類型別名語法支援建立別名模板:

template<typename T> using ptr = T*;   

// the name 'ptr<T>' is now an alias for pointer to T  
ptr<int> ptr_int;  

示例

以下示例說明如何將別名模板與typedef一起使用 - 在此示例中,它是一個整數向量型別。 你可以替換為任何型別int在主功能程式碼中建立方便的別名,以便隱藏複雜的引數列表。 通過在程式碼中使用自定義分配器,你可以提高可讀性並降低引入由拼寫錯誤導致的 Bug 的風險。

#include <stdlib.h>  
#include <new>  

template <typename T> struct MyAlloc {  
    typedef T value_type;  

    MyAlloc() { }  
    template <typename U> MyAlloc(const MyAlloc<U>&) { }  

    bool operator==(const MyAlloc&) const { return true; }  
    bool operator!=(const MyAlloc&) const { return false; }  

    T * allocate(const size_t n) const {  
        if (n == 0) {  
            return nullptr;  
        }  

        if (n > static_cast<size_t>(-1) / sizeof(T)) {  
            throw std::bad_array_new_length();  
        }  

        void * const pv = malloc(n * sizeof(T));  

        if (!pv) {  
            throw std::bad_alloc();  
        }  

        return static_cast<T *>(pv);  
    }  

    void deallocate(T * const p, size_t) const {  
        free(p);  
    }  
};  

#include <vector>  
using MyIntVector = std::vector<int, MyAlloc<int>>;  

#include <iostream>  

int main ()   
{  
    MyIntVector foov = { 1701, 1764, 1664 };  

    for (auto a: foov) std::cout << a << " ";  
    std::cout << "\n";  

    return 0;  
}  

Output

1701 1764 1664  

Typedef

一個typedef宣告引入的名稱在其範圍內,將成為給定的型別的同義詞型別宣告一部分的宣告。

使用 typedef 宣告,可以為已由語言定義的型別和對你已宣告的型別構造更短或更有意義的名稱。 利用 Typedef 名稱,您可以封裝可能會發生更改的實現詳細資訊。

classstructunion,以及enum宣告相反, typedef宣告不引入新型別-它們引入現有型別的新名稱。

使用宣告的名稱typedef與其他識別符號 (不包括語句標籤)佔用相同的名稱空間。 因此,它們不能使用與前一個宣告的名稱相同的識別符號(除了在類型別宣告中)。 請看下面的示例:

// typedef_names1.cpp  
// C2377 expected  
typedef unsigned long UL;   // Declare a typedef name, UL.  
int UL;                     // C2377: redefined.  

隱藏名稱規則也控制typedef宣告的名稱的可見性。 因此,以下示例在 C++ 中是合法的:

// typedef_names2.cpp  
typedef unsigned long UL;   // Declare a typedef name, UL  
int main()  
{  
   unsigned int UL;   // Redeclaration hides typedef name  
}  

// typedef UL back in scope  
// typedef_specifier1.cpp  
typedef char FlagType;  

int main()  
{  
}  

void myproc( int )  
{  
    int FlagType;  
}  

當通過與 typedef 相同的名稱宣告本地範圍識別符號時,或者在同一範圍內或內部範圍內宣告結構或聯合的成員時,必須指定型別說明符。 例如:

typedef char FlagType;  
const FlagType x;  

若要對識別符號、結構成員或聯合成員重用 FlagType 名稱,則必須提供型別:

const int FlagType;  // Type specifier required  

僅僅編寫以下語句是不夠的

const FlagType;      // Incomplete specification  

由於 FlagType 被當做該型別的一部分,因此沒有要重新宣告的識別符號。 此宣告被視為非法宣告,例如

int;  // Illegal declaration   

可以使用 typedef 宣告任何型別,包括指標、函式和陣列型別。 只要定義具有與宣告相同的可見性,那麼在定義結構或聯合型別之前,您就可以為指向結構或聯合型別的指標宣告 typedef 名稱。

示例

typedef用途是使宣告更加統一和精簡。 例如:

typedef char CHAR;          // Character type.  
typedef CHAR * PSTR;        // Pointer to a string (char *).  
PSTR strchr( PSTR source, CHAR target );  
typedef unsigned long ulong;  
ulong ul;     // Equivalent to "unsigned long ul;"  

若要使用typedef在同一宣告中指定基本和派生型別,可以使用逗號分隔宣告符。 例如:

typedef char CHAR, *PSTR;  

下面的示例為不返回值並採用兩個 int 引數的函式提供了型別 DRAWF

typedef void DRAWF( int, int );  

在上述typedef語句中,宣告

DRAWF box;   

將等效於宣告

void box( int, int );  

typedef通常與結合結構來宣告和命名使用者定義型別:

// typedef_specifier2.cpp  
#include <stdio.h>  

typedef struct mystructtag  
{  
    int   i;  
    double f;  
} mystruct;  

int main()  
{  
    mystruct ms;  
    ms.i = 10;  
    ms.f = 0.99;  
    printf_s("%d   %f\n", ms.i, ms.f);  
}  

Output

10   0.990000  

typedef 的重新宣告

Typedef宣告可用於重新宣告相同的名稱來引用相同的型別。 例如:

// FILE1.H  
typedef char CHAR;  

// FILE2.H  
typedef char CHAR;  

// PROG.CPP  
#include "file1.h"  
#include "file2.h"   // OK  

該程式包括兩個標標頭檔案,這兩個包含typedef名稱宣告CHAR。 只要兩個宣告都引用同一個型別,則此類重新宣告是可以接受的。

一個typedef不能重新定義為與之前宣告不同型別的名稱。 因此,如果FILE2.H包含

// FILE2.H  
typedef int CHAR;     // Error  

由於嘗試了將名稱 CHAR 重新宣告為引用不同型別,編譯器引發了錯誤。 此錯誤的影響範圍包含了構造,例如:

typedef char CHAR;  
typedef CHAR CHAR;      // OK: redeclared as same type  

typedef union REGS      // OK: name REGS redeclared  
{                       //  by typedef name with the  
    struct wordregs x;  //  same meaning.  
    struct byteregs h;  
} REGS;  

以下語言中的 Typedef:C++ 與C

利用typedef說明符與class型別的很頻繁,很大程度上是因為typedef宣告的未命名的結構的 ANSI C 操作。 例如,許多 C 程式設計師都使用:

// typedef_with_class_types1.cpp  
// compile with: /c  
typedef struct {   // Declare an unnamed structure and give it the  
                   // typedef name POINT.  
   unsigned x;  
   unsigned y;  
} POINT;  

此類宣告的優點是它允許如下宣告:

POINT ptOrigin;  

而不是:

struct point_t ptOrigin;  

在 c + + ,typedef名稱和實際型別(結構聯合,和列舉)之 間的差異更為明顯。 儘管宣告無名稱結構中的 C 做法typedef語句仍有效,它提供了無符號的優勢,在 C 中一樣

// typedef_with_class_types2.cpp  
// compile with: /c /W1  
typedef struct {  
   int POINT();  
   unsigned x;  
   unsigned y;  
} POINT;  

上面的示例宣告一個名為類POINT使用未命名的類typedef語法。 POINT 被視為類名稱;但是,以下限制適用於通過這種方式引入的名稱:

  • 名稱 (代名稱) 不能出現結構,或聯合字首之後。

  • 名稱不能用作類宣告中的建構函式名稱或解構函式名稱。

    總之,該語法不提供針對繼承、構造或析構的任何機制。