C++11中enum class的使用


本文鏈接:https://blog.csdn.net/fengbingchun/article/details/78535754

枚舉類型(enumeration)使我們可以將一組整型常量組織在一起。和類一樣,每個枚舉類型定義了一種新的類型。枚舉屬於字面值常量類型。

C++包含兩種枚舉:限定作用域的和不限定作用域的。這里主要介紹限定作用域的。不限定作用域的使用可以參考: http://blog.csdn.net/fengbingchun/article/details/51778977

C++11新標准引入了限定作用域的枚舉類型(scoped enumeration)。定義限定作用域的枚舉類型的一般形式是:首先是關鍵字enum class(或者等價地使用enum struct),隨后是枚舉類型名字以及用花括號括起來的以逗號分隔的枚舉成員(enumerator)列表,最后是一個分號。

枚舉作用域(enumeration scope)是指枚舉類型的成員的名字的作用域,起自其聲明之處,終止枚舉定義結束之處。C語言規定,枚舉類型的成員(enumerator)的可見范圍被提升至該枚舉類型所在的作用域內。這被認為有可能污染了外部的作用域,為此,C++11引入了枚舉類(enum class)解決此問題。

定義不限定作用域的枚舉類型(unscoped enumeration)時省略掉關鍵字class(或struct),枚舉類型的名字是可選的。

如果enum是未命名的,則我們只能在定義該enum時定義它的對象。和類的定義類似,我們需要在enum定義的右側花括號和最后的分號之間提供逗號分隔的聲明列表。

枚舉成員:在限定作用域的枚舉類型中,枚舉成員的名字遵循常規的作用域准則,並且在枚舉類型的作用域外是不可訪問的。與之相反,在不限定作用域的枚舉類型中,枚舉成員的作用域與枚舉類型本身的作用域相同。

默認情況下,枚舉值從0開始,依次加1.不過我們也能為一個或幾個枚舉成員指定專門的值。枚舉值不一定唯一。如果我們沒有顯示地提供初始值,則當前枚舉成員的值等於之前枚舉成員的值加1.枚舉成員是const,因此在初始化枚舉成員時提供的初始值必須是常量表達式。也就是說,每個枚舉成員本身就是一條常量表達式,我們可以在任何需要常量表達式的地方使用枚舉成員。類似的,我們也可以將一個enum作為switch語句的表達式,而將枚舉值作為case標簽。出於同樣的原因,我們還能將枚舉類型作為一個非類型模板形參使用;或者在類的定義中初始化枚舉類型的靜態數據成員。

和類一樣,枚舉也定義新的類型:只要enum有名字,我們就能定義並初始化該類型的成員。要想初始化enum對象或者為enum對象賦值,必須使用該類型的一個枚舉成員或者該類型的另一個對象

一個不限定作用域的枚舉類型的對象或枚舉成員自動地轉換成整型。因此,我們可以在任何需要整型值的地方使用它們。而限定作用域的枚舉類型不會進行隱式轉換

指定enum的大小:盡管每個enum都定義了唯一的類型,但實際上enum是由某種整數類型表示的。在C++11標准中,我們可以在enum的名字后加上冒號以及我們想在該enum中使用的類型。如果我們沒有指定enum的潛在類型,則默認情況下限定作用域的enum成員類型是int。對於不限定作用域的枚舉類型來說,其枚舉成員不存在默認類型,我們只知道成員的潛在類型足夠大,肯定能夠容納枚舉值。如果我們指定了枚舉成員的潛在類型(包括對限定作用域的enum的隱式指定),則一旦某個枚舉成員的值超出了該類型所能容納的范圍,將引發程序錯誤。

指定enum潛在類型的能力使得我們可以控制不同實現環境中使用的類型,我們將可以確保在一種實現環境中編譯通過的程序所生成的代碼與其他實現環境中生成的代碼一致。

枚舉類型的前置聲明:在C++11新標准中,我們可以提前聲明enum。enum的前置聲明(無論隱式地還是顯示地)必須指定其成員的大小。不限定作用域的,必須指定成員類型。限定作用域的枚舉類型可以使用默認成員類型int。因為不限定作用域的enum未指定成員的默認大小,因此每個聲明必須指定成員的大小。對於限定作用域的enum來說,我們可以不指定其成員的大小,這個值被隱式地定義成int。和其它聲明語言一樣,enum的聲明和定義必須匹配,這意味着在該enum的所有聲明和定義中成員的大小必須一致。而且,我們不能在同一個上下文中先聲明一個不限定作用域的enum名字,然后再聲明一個同名的限定作用域的enum。

形參匹配與枚舉類型:要想初始化一個enum對象,必須使用該enum類型的另一個對象或者它的一個枚舉成員。因此,即使某個整型值恰好與枚舉成員的值相等,它也不能作為函數的enum實參使用。不限定作用域的枚舉類型,潛在類型因機器而異。盡管我們不能直接將整型值傳給enum實參,但是可以將一個不限定作用域的枚舉類型的對象或枚舉成員傳給整型形參。此時,enum的值提升成int或更大的整型,實際提升的結果由枚舉類型的潛在類型決定。

The enum classes("new enums", "strong enums") address three problems with traditional C++ enumerations:

1. conventional enums implicitly convert to int, causing errors when someone does not want an enumeration to act as an integer.

2. conventional enums export their enumerators to the surrounding scope, causing name clashes.

3. the underlying type of an enum cannot be specified, causing confusion,compatibility problems, and makes forward declaration impossible.

The new enums are "enum class" because they combine aspects of traditional enumerations (names values) with aspects of classes (scoped members and absense of conversions).

C++ has two kinds of enum: enum classes,Plain enums.

下面是從其他文章中copy的測試代碼,詳細內容介紹可以參考對應的reference:

 

#include "enum_class.hpp"
#include <iostream>

namespace enum_class_ {

typedef short int16_t;

////////////////////////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/language/enum
// enum that takes 16 bits
enum smallenum : int16_t {
	a,
	b,
	c
};

// color may be red (value 0), yellow (value 1), green (value 20), or blue (value 21)
enum color {
	red,
	yellow,
	green = 20,
	blue
};

// altitude may be altitude::high or altitude::low
enum class altitude : char {
	high = 'h',
	low = 'l', // C++11 allows the extra comma
};

// the constant d is 0, the constant e is 1, the constant f is 3
enum {
	d,
	e,
	f = e + 2
};

//enumeration types (both scoped and unscoped) can have overloaded operators
std::ostream& operator << (std::ostream& os, color c)
{
	switch (c) {
		case red: os << "red";    break;
		case yellow: os << "yellow"; break;
		case green: os << "green";  break;
		case blue: os << "blue";   break;
		default: os.setstate(std::ios_base::failbit);
	}

	return os;
}

std::ostream& operator << (std::ostream& os, altitude al)
{
	return os << static_cast<char>(al);
}

int test_enum_class_1()
{
	color col = red;
	altitude a;
	a = altitude::low;

	std::cout << "col = " << col << '\n'
		<< "a = " << a << '\n'
		<< "f = " << f << '\n';

	return 0;
}

////////////////////////////////////////////////////////////////////////
// reference: https://stackoverflow.com/questions/18335861/why-is-enum-class-preferred-over-plain-enum
// C++ has two kinds of enum: enum classes, Plain enums
enum Color { red1, green1, blue1 };                    // plain enum
enum Card { red_card, green_card, yellow_card };    // another plain enum
enum class Animal { dog, deer, cat, bird, human };  // enum class
enum class Mammal { kangaroo, deer, human };        // another enum class

int test_enum_class_2()
{
	// examples of bad use of plain enums:
	Color color = Color::red1;
	Card card = Card::green_card;

	int num = color;    // no problem

	if (color == Card::red_card) // no problem (bad)
		std::cout << "bad" << std::endl;

	if (card == Color::green1)   // no problem (bad)
		std::cout << "bad" << std::endl;

	// examples of good use of enum classes (safe)
	Animal a = Animal::deer;
	Mammal m = Mammal::deer;

	//int num2 = a;   // error
	//if (m == a)     // error (good)
	//	std::cout << "bad" << std::endl;

	//if (a == Mammal::deer) // error (good)
	//	std::cout << "bad" << std::endl;

	return 0;
}

////////////////////////////////////////////////////////
// reference: http://www.learncpp.com/cpp-tutorial/4-5a-enum-classes/
int test_enum_class_3()
{
	enum class Color { // "enum class" defines this as an scoped enumeration instead of a standard enumeration
		RED, // RED is inside the scope of Color
		BLUE
	};

	enum class Fruit {
		BANANA, // BANANA is inside the scope of Fruit
		APPLE
	};

	Color color = Color::RED; // note: RED is not directly accessible any more, we have to use Color::RED
	Fruit fruit = Fruit::BANANA; // note: BANANA is not directly accessible any more, we have to use Fruit::BANANA

	//if (color == fruit) // compile error here, as the compiler doesn't know how to compare different types Color and Fruit
	//	std::cout << "color and fruit are equal\n";
	//else
	//	std::cout << "color and fruit are not equal\n";

	if (color == Color::RED) // this is okay
		std::cout << "The color is red!\n";
	else if (color == Color::BLUE)
		std::cout << "The color is blue!\n";

	//std::cout << color; // won't work, because there's no implicit conversion to int
	color = Color::BLUE;
	std::cout << static_cast<int>(color) << std::endl; // will print 1

	return 0;
}

} // namespace enum_class_

GitHubhttps://github.com/fengbingchun/Messy_Test

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM