C++ 总结 (一、基础篇)
C++ 完全兼容C语言,但是有自己的语法特点,本文总结了C++的基础知识。记录如下
基本输入输出
命名空间。using namespace std; 或者使用 std::cout;
cout << "nihao";
cin >> a;
getline(cin, string);
函数 functions
通常函数(C/C++),函数调用是值传递,外部实参将变量的值传给形参,函数内部创建新变量并copy实参的值。函数内部的操作不会影响外部实参。
function_arguments.png引用传递的函数,C 和 C++ 不同,C语言中是参数类型为指针,如下void duplicate (int* a, int* b, int* c)
,函数内部根据指针获取外部变量。C++ 中有优化,如下 void duplicate (int& a, int& b, int& c)
两种方式都是引用传递。
C++ 中是直接引用传递,函数内部参数与外界实参是同一个,此类函数通常用来修改外界变量值。
效率问题
采用值传递会copy传入的变量值,赋值给函数内部形参。这个操作对于基本数据类型没效率问题。
对于 string 等符合类型有效率问题,这种情况使用引用传递如果不允许函数内部改写外部值,可在参数声明时加入 const 声明
// 基本类型值传递
void duplicate (int a, int b, int c)
// 基本类型引用传递
void duplicate (int& a, int& b, int& c)
// 符合类型值传递 - 有效率问题
string concatenate (string a, string b)
{
return a+b;
}
// 符合类型引用传递 - 内部可以直接修改外部变量
string concatenate (string& a, string& b)
{
return a+b;
}
// 符合类型引用传递 - 内部不可修改外部变量
string concatenate (const string& a, const string& b)
{
return a+b;
}
内联函数
C++ 中关键字 inline
, 用于函数声明之前,它不会改变函数本身的行为。
它的调用机制与一般的函数调用机制不同,会在调用的时候直接将函数展开(减少压栈,提高效率)执行。
inline string concatenate (const string& a, const string& b)
{
return a+b;
}
注意
inline 说明符只是告诉编译器此函数可以内联
事实上,现代编译器为了优化效率会在合适的时机将函数内联,inline 说明符只是建议内联,编译器仍旧会根据实际情况才处理(如上函数会内联,如操作巨复杂的函数即时写了 inline 仍旧不会内联)。
C++ 的内联操作本身也是委托给编译器处理的,编译器有最终的决定权。
函数重载与模板函数
函数重载 overload : 只函数名相同,但是参数类型不同,事实上是不同函数的函数。只有返回值类型不同不构成重载,系统会根据调用时候传入的参数类型找到正确的函数调用。
int operate (int a, int b)
{
return (a*b);
}
double operate (double a, double b)
{
return (a/b);
}
上面 operate 就是被重载成了两个函数,实际上上开发中并不需要这样做。通常对同样的函数,传入不同参数我们希望是同样的操作,这可以用模板函数来实现,格式
// 格式
template <template-parameters> function-declaration
// egg:class 是为了指定 typename,事实上可以class 可以换成 typename 关键字
template <class SomeType>
SomeType sum (SomeType a, SomeType b)
{
return a+b;
}
// 使用
#include <iostream>
using namespace std;
template <class T>
T sum (T a, T b)
{
T result;
result = a + b;
return result;
}
int main () {
int i=5, j=6, k;
double f=2.0, g=0.5, h;
k=sum<int>(i,j);
h=sum<double>(f,g);
cout << k << '\n';
cout << h << '\n';
return 0;
}
还有一种无类型模板函数。类似函数中默认值。只是在模板函数中的默认类型是在编译期间
确定的,使用的时候只能传递一个常量,在运行时是不可以改变的,如下。
#include <iostream>
using namespace std;
// 第一个参数为模板指定参数,第二个参数为编译时期确定
template <class T, int N>
T fixed_multiply (T val)
{
return val * N;
}
int main() {
// 使用时,只需要传第一个参数,第二个参数只能是常数
std::cout << fixed_multiply<int,2>(10) << '\n';
std::cout << fixed_multiply<int,3>(10) << '\n';
}
名称可见性与命名空间
变量可以创建在不同作用域内: 全局/局部
在同一个作用域内,只有一个实体可以使用某个具体的名字。C++ 中引入了命名空间概念来包含其他作用域的声明的实体,最著名的为 std. 通过使用 using namespace std; 可以在自己的代码中引用标准库中定义的函数、变量声明。
命名空间可分开定义,它可以贯穿整个源码使用。命名空间可以设置别名。namespace new_name = current_name;
// using namespace example
#include <iostream>
using namespace std;
namespace first
{
int x = 5;
}
namespace second
{
double x = 3.1416;
}
int main () {
{
using namespace first;
cout << x << '\n';
}
{
using namespace second;
cout << x << '\n';
}
return 0;
}
// -----
5
3.1416
变量的存储类型
变量的存储类型
- 静态存储类型, 全局变量 - 程序生命周期只有一份内存,会被初始化为 0
- 动态存储类型, 局部变量 - 运行时在作用域内随机分配的内存,内存存在随机数据(包括0)
全局变量和命名空间作用域的变量 -> 其内存是在整个程序生命周期中分配的。它会被初始化为 0.
局部变量是在其作用域内声明和使用的,在运行时中同样的内存可能被分配个多个变量,其值为不确定的(包括0)
数组
C++ 完全继承了 C 语言内建的数组功能。数组就是连续同一种类型的内存,可以通过下标访问。其声明格式type name [elements];
,通常会在声明的时候进行初始化值,如 int foo [5] = { 16, 2, 77, 40, 12071 };
C++ 中允许声明赋值的时候不显示写明数组长度。
int foo[] = { 10, 20, 30 };
int foo[] { 10, 20, 30 };
// 多维数组 - 本质上在内存中也是整体一维。分配15 个 int 长度。
int jimmy [3][5];
// 数组传参 - 最外围数组只传递指针,需要额外的数组长度的参数。
void procedure (int myarray[])
void procedure (int myarray[][3][4])
数组作为参数的时候,由于无法复制的原因,会传递数组的指针,所以参数为数组的函数需要额外加一个数组长度的参数。多维数组入参,其外围数组可以无需标明数组容量,但是其他子集需要指明其容量。
C++ 标准库数组
C++ 继承了 C 语言的数组,同时也提供了标准库的数组实现。与C语言区别如下
- 需要引入标准库头文件
#include <array>
- 数组声明(基于模板函数的方式)
- 提供了 .size() 等方便访问其长度的方法
----- 使用语言内建的数组 继承自 C
#include <iostream>
using namespace std;
int main()
{
int myarray[3] = {10,20,30};
for (int i=0; i<3; ++i)
++myarray[i];
for (int elem : myarray)
cout << elem << '\n';
}
----- 使用 C++ 标准库中的数组,
#include <iostream>
#include <array>
using namespace std;
int main()
{
array<int,3> myarray {10,20,30};
for (int i=0; i<myarray.size(); ++i)
++myarray[i];
for (int elem : myarray)
cout << elem << '\n';
}
字符串
字符串实际上就是字符数组。简单定义:char foo[20];
声明并开辟了一个 20 char 长度的连续空间存储一序列字符,但默认其空间的值都是为定义的。它的容量可以存储“Hello”也可以存储“Merry Christmas”, 字符串默认尾部会加一个null
结束符,其字符表示为\0
。
字符串声明并初始化 && 字面量字符串
// 声明并初始化 - 隐式指定字符串长度 - 末尾 '\0' 结尾
char myword[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
// 字面量字符串 - 字面量字符串也是默认以 '\0' 结尾
char myword[] = "Hello";
注意
因为字符串本质是字符数组,具有数组的限制: 它只能在初始化的时赋值,不能在之后对其变量进行赋值
当然其内部值可以变,如 myword[2] = 'w';
C++ 标准库中的 Strings
普通字符数组类型的字符串是 C 语言字符串,C++ 标准库定义了 string 类来表示字符串,但是我们使用的字符串字面量的形式仍然是 C 语言风格的字符串,其结尾依旧是 '\0';
在 C++ 标准库中两种字符串是共存且可以互相转换的。如下
// strings and NTCS:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
char question1[] = "What is your name? ";
string question2 = "Where do you live? ";
char answer1 [80];
string answer2;
cout << question1;
cin >> answer1;
cout << question2;
cin >> answer2;
cout << "Hello, " << answer1;
cout << " from " << answer2 << "!\n";
return 0;
}
----------------------------
What is your name? Homer
Where do you live? Greece
Hello, Homer from Greece!
----------------------------------
char myntcs[] = "some text";
string mystring = myntcs; // convert c-string to string
cout << mystring; // printed as a library string
cout << mystring.c_str(); // printed as a c-string
注意:string 类型的 c_str() 和 data() 两个方法是完全相等的
指针
指针是一种变量,存储其同类变量的地址值。如int *ptr = &a
操作系统中内存是以字节为单位连续存储的。 定义的变量名是可以访问某个内存单位的名字,程序可以直接通过变量名访问对应的虚拟内存。
变量被声明时,系统会将创建变量所需的内存地址赋值给变量名(换言之:变量名就是变量在内存中首地址)。
取地址符(&) 和接触引用操作符 ()*
-
&
is the address-of operator, and can be read simply as "address of" -
*
is the dereference operator, and can be read as "value pointed to by"
foo = &myvar;
myvar = 25;
foo = &myvar;
bar = myvar;
reference_operator.png
// baz 等于 foo 指针指向的值
baz = *foo;
dereference_operator.png
定义指针与简单使用
指针定义 type *ptr;
使用如下
// more pointers
#include <iostream>
using namespace std;
int main ()
{
int firstvalue = 5, secondvalue = 15;
int * p1, * p2;
p1 = &firstvalue; // p1 = address of firstvalue
p2 = &secondvalue; // p2 = address of secondvalue
*p1 = 10; // value pointed to by p1 = 10
*p2 = *p1; // value pointed to by p2 = value pointed to by p1
p1 = p2; // p1 = p2 (value of pointer is copied)
*p1 = 20; // value pointed to by p1 = 20
cout << "firstvalue is " << firstvalue << '\n';
cout << "secondvalue is " << secondvalue << '\n';
return 0;
}
指针与数组
数组本质上是一串连续内存。其数组名即其首元素的地址,即数组的指针
int myarray [20];
int * mypointer;
// 数组名赋值给指针 - 是合法的
mypointer = myarray;
// 数组名内存只能指向声明时分配的内存 - 操作非法
myarray = mypointer;
因为指针是可以指向其他地址的,mypointer 可以重新赋值。但是 myarray 只能指向声明时候分配的标识数组的 20 个地址,并且永远无法改变。所以无法给 myarray 赋值,如上。
指针指向数组首地址,其用法与数组一样,如下
// more pointers
#include <iostream>
using namespace std;
int main ()
{
int numbers[5];
int * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
return 0;
}
// --- 10, 20, 30, 40, 50,
// 以下操作相同且合法
a[5] = 0; // a [offset of 5] = 0
*(a+5) = 0; // pointed to by (a+5) = 0
指针初始化 & 算术操作
初始化类似变量的声明与初始化,如下
int myvar;
int * myptr = &myvar;
int myvar;
int * myptr = &myvar;
int myvar;
int * myptr;
*myptr = &myvar;
int myvar;
int *foo = &myvar;
int *bar = foo;
指针的加减:其加减单位为类型所占字节长度。
char *mychar;
short *myshort;
long *mylong;
// 三种不同类型的指针执行 ++ 操作
++mychar;
++myshort;
++mylong;
// ++ 操作符优先级高于 * 优先级
*p++ // same as *(p++): increment pointer, and dereference unincremented address
*++p // same as *(++p): increment pointer, and dereference incremented address
++*p // same as ++(*p): dereference pointer, and increment the value it points to
(*p)++ // dereference pointer, and post-increment the value it points to
// 一个常见包含 ++ 和 * 操作符的语句
*p++ = *q++;
// 由于 ++ 优先级高,其整体操作等价于
*p = *q;
++p;
++q;
指针自加操作示意图
pointer_arithmetics.png
指针和 const
指针可以通过地址访问变量,也可以修改其指向变量的值。
const 修饰符可以限定只读指针:即只能读取变量值,无法修改变量值
int x;
int y = 10;
const int * p = &y; // 注意 const 变量位置
x = *p; // ok: reading p
*p = x; // error: modifying p, which is const-qualified
注意:
const 修饰符,其修饰 int * 类型时,表明int 变量值不可变。其修饰变量 p 时,p 变量值不可变。
const int * p = &y;
和 int const* p = &y;
相同。
// 仔细体会一下 const 具体修饰的位置
int x;
int * p1 = &x; // non-const pointer to non-const int
const int * p2 = &x; // non-const pointer to const int
int * const p3 = &x; // const pointer to non-const int
const int * const p4 = &x; // const pointer to const int
常量指针使用 demo
// pointers as arguments:
#include <iostream>
using namespace std;
void increment_all (int* start, int* stop)
{
int * current = start;
while (current != stop) {
++(*current); // increment value pointed
++current; // increment pointer
}
}
void print_all (const int* start, const int* stop)
{
const int * current = start;
while (current != stop) {
cout << *current << '\n';
++current; // increment pointer
}
}
int main ()
{
int numbers[] = {10,20,30};
increment_all (numbers,numbers+3);
print_all (numbers,numbers+3);
return 0;
}
指针与字面量字符串
字面量字符串本质是不可变常量字符串,如下,指针 foo 指向的是 “hello” 首地址。
const char * foo = "hello";
pointer_assignment.png
字符串访问某字符可以通过数组下标也可以通过指针访问
*(foo+4)
foo[4]
指向指针的指针(二维指针 - 二维数组)
指针同样可以被其他指针指向
char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b; // c 就是指向指针 b 的指针。它是一个二维指针
- c is of type char** and a value of 8092
- c is of type char and a value of 7230
- **c is of type char and a value of 'z'
它们在内存中关系如下
pointer_to_pointer.png
void 指针
void 指针即 void *, 它是不具备具体类型的指针,或者叫做任意类型指针。
说白了就是某块内存的首地址,但是未指定具体类型,如 int */ char * 等多种类型它都可以直接指向,但是未明确具体每个元素的长度,如果使用就必须告知其每个元素的长度。如下:
// increaser
#include <iostream>
using namespace std;
void increase (void* data, int psize)
{
if ( psize == sizeof(char) )
{ char* pchar; pchar=(char*)data; ++(*pchar); }
else if (psize == sizeof(int) )
{ int* pint; pint=(int*)data; ++(*pint); }
}
int main ()
{
char a = 'x';
int b = 1602;
increase (&a,sizeof(a));
increase (&b,sizeof(b));
cout << a << ", " << b << '\n';
return 0;
}
//-------------
y, 1603
sizeof 操作符是一个编译器指令,在编译阶段会直接由编译器翻译成常数:如 sizeof(int) 在编译阶段直接会被翻译成常数 4,sizeof(char) 在编译阶段直接会被翻译成常数 1.
无效指针 和 指向空的指针
无效指针,也是通常说的野指针。指的是访问了无权限地址的指针。野指针在编译期间不会报错,因为它符合语法,但是运行时会因为访问了无分配权限的地址而导致崩溃。如下
int * p; // uninitialized pointer (local variable)
int myarray[10];
int * q = myarray+20; // element out of bounds
空指针,指的是指向空的指针,类似于 OC 里面将指针指向 nil。C++ 中定义方法有三种,都代表将指针指向地址0;
int * p = 0;
int * q = nullptr;
int * r = NULL;
指针和函数
通常,函数指针是用在将函数作为参数传递的时候,函数指针写法如 int (* minus)(int,int) = subtraction;
。 具体使用如下:
// pointer to functions
#include <iostream>
using namespace std;
int addition (int a, int b)
{ return (a+b); }
int subtraction (int a, int b)
{ return (a-b); }
int operation (int x, int y, int (*functocall)(int,int))
{
int g;
g = (*functocall)(x,y);
return (g);
}
int main ()
{
int m,n;
int (*minus)(int,int) = subtraction;
m = operation (7, 5, addition);
n = operation (20, m, minus);
cout <<n;
return 0;
}
// -------
8
动态内存
通常,程序运行之前(编译时期)即已确定了其定义变量所需的内存容量。
但是,对于用户从键盘录入的内容只能在运行时动态分配内存。
对于动态内存的分配和释放,C++ 提供了 new 和 delete 关键字。
开辟空间 new
和 new []
, new
只能开辟一块相对类型的空间,new []
可以开辟连续的一组空间
int * foo;
foo = new int [5];
dynamic.png
对于开辟空间,有时候会出错,出错可以使用两种方式处理,1.抛出异常,2.不抛异常,直接判断开辟的空间指针是否为nil,如下
int * foo;
foo = new (nothrow) int [5];
if (foo == nullptr) {
// error assigning memory. Take measures.
}
删除动态内存,delete
和 delete []
,分别是删除一块空间和一块连续的内存,其中被释放的内存,必须是之前 new 出来的,或者是 nullPtr;
delete pointer;
delete[] pointer;
看一个完整的 Demo
// rememb-o-matic
#include <iostream>
#include <new>
using namespace std;
int main ()
{
int i,n;
int * p;
cout << "How many numbers would you like to type? ";
cin >> i;
p= new (nothrow) int[i];
if (p == nullptr)
cout << "Error: memory could not be allocated";
else
{
for (n=0; n<i; n++)
{
cout << "Enter number: ";
cin >> p[n];
}
cout << "You have entered: ";
for (n=0; n<i; n++)
cout << p[n] << ", ";
delete[] p;
}
return 0;
}
// -------------
How many numbers would you like to type? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067, 8, 32,
需要注意的是: p= new (nothrow) int[i];
开辟内存的数量取决于用户输入,如果输入特别大数字,可能就遇到开辟空间错误问题,所以需要做错误处理。
Note
C 语言的动态内存分配函数: malloc, calloc, realloc and free 在 C++ 环境之下完全兼容,但是内存的分配和释放都需要在同一套函数之内。
数据结构(Data structures) - 结构体
结构体是一组共用同一个名称的元素集合。其中每个元素叫做成员,成员可以有自己的类型和长度。通过结构体可以构成面向对象的基础,如
// 语法规则 -
struct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
...
} object_names;
// 使用1, 通过 struct product 定义一个新的 product 类型,后面可以直接使用新的product类型
struct product {
int weight;
double price;
} ;
product apple;
product banana, melon;
// 使用2,直接在定义类型的同时,声明结构体变量 --- 完全等同于使用方式1
struct product {
int weight;
double price;
} apple, banana, melon;
结构体变量可以直接通过点语法访问自己内部成员。一个完整使用结构体示例
// example about structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct movies_t {
string title;
int year;
} mine, yours;
void printmovie (movies_t movie);
int main ()
{
string mystr;
mine.title = "2001 A Space Odyssey";
mine.year = 1968;
cout << "Enter title: ";
getline (cin,yours.title);
cout << "Enter year: ";
getline (cin,mystr);
stringstream(mystr) >> yours.year;
cout << "My favorite movie is:\n ";
printmovie (mine);
cout << "And yours is:\n ";
printmovie (yours);
return 0;
}
void printmovie (movies_t movie)
{
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
// ---------------------
Enter title: Alien
Enter year: 1979
My favorite movie is:
2001 A Space Odyssey (1968)
And yours is:
Alien (1979)
结构体定义的是一种类型,他们也可以用作数组的方式来构造他们的表、或者数据库,如下
// array of structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct movies_t {
string title;
int year;
} films [3];
void printmovie (movies_t movie);
int main ()
{
string mystr;
int n;
for (n=0; n<3; n++)
{
cout << "Enter title: ";
getline (cin,films[n].title);
cout << "Enter year: ";
getline (cin,mystr);
stringstream(mystr) >> films[n].year;
}
cout << "\nYou have entered these movies:\n";
for (n=0; n<3; n++)
printmovie (films[n]);
return 0;
}
void printmovie (movies_t movie)
{
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
// ------------------
Enter title: Blade Runner
Enter year: 1982
Enter title: The Matrix
Enter year: 1999
Enter title: Taxi Driver
Enter year: 1976
You have entered these movies:
Blade Runner (1982)
The Matrix (1999)
Taxi Driver (1976)
指针与结构体
和其他类型一样,结构体也可以使用指向该类型的指针指向。
struct movies_t {
string title;
int year;
};
movies_t amovie;
movies_t * pmovie;
// 可以将amovie的地址赋值给 pmovie 变量
pmovie = &amovie;
示例
// pointers to structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct movies_t {
string title;
int year;
};
int main ()
{
string mystr;
movies_t amovie;
movies_t * pmovie;
pmovie = &amovie;
cout << "Enter title: ";
getline (cin, pmovie->title);
cout << "Enter year: ";
getline (cin, mystr);
(stringstream) mystr >> pmovie->year;
cout << "\nYou have entered:\n";
cout << pmovie->title;
cout << " (" << pmovie->year << ")\n";
return 0;
}
// ------------------
Enter title: Invasion of the body snatchers
Enter year: 1978
You have entered:
Invasion of the body snatchers (1978)
结构体变量访问本身成员可以用点语法。
结构体指针访问其成员变量需要箭头操作符(->).
下图展示了点语法和(->)操作符的区别
<div>Expression<span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space: pre;"></span></div> | What is evaluated | Equivalent |
---|---|---|
a.b | Member b of object a | |
a->b | Member b of object pointed to by a | (*a).b |
*a.b | Value pointed to by member b of object a | *(a.b) |
结构体嵌套
结构体内可以嵌套其他结构体
struct movies_t {
string title;
int year;
};
struct friends_t {
string name;
string email;
movies_t favorite_movie;
} charlie, maria;
friends_t * pfriends = &charlie;
基于上面的定义,可以通过如下的代码访问具体结构体内容(最后两行代码是访问同样的成员)
charlie.name
maria.favorite_movie.title
charlie.favorite_movie.year
pfriends->favorite_movie.year
其他类型 - 类型别名/共用体/枚举
定义类型别名有两种方式: typedef && using
格式: typedef existing_type new_type_name ;
示例
typedef char C;
typedef unsigned int WORD;
typedef char * pChar;
typedef char field [50];
格式: using new_type_name = existing_type ;
示例
using C = char;
using WORD = unsigned int;
using pChar = char *;
using field = char [50];
两种创建别名的方式本质相同,前者继承自 C 语言,后者为 C++ 提供,using 用于模板函数的时候更加通用。使用别名的优势:使用自定义类型,如果代码后期修改数据类型,可以直接在别名定义出修改。
共用体 unions
共用体是一种新类型,它很像像结构体但其内部成员共用同一块物理内存。整个共用体的内存大小取决于其最大的内部成员。由于内部成员共同占用同一块内存、所以改变任何一个成员变量的值都会影响整个结构的值。因为真实的内存对齐方式依赖于机器环境,共用体在移植性上可能有问题
union mix_t {
int l;
struct {
short hi;
short lo;
} s;
char c[4];
} mix;
假定操作系统32位小端模式,int 占 4 字节,short 2 字节。上述代码的内存占用情况如下:
union.png匿名共用体
共用体定义在 class 或 struct 中可以不定义名称。
// structure with regular union
struct book1_t {
char title[50];
char author[50];
union {
float dollars;
int yen;
} price;
} book1;
// structure with anonymous union
struct book2_t {
char title[50];
char author[50];
union {
float dollars;
int yen;
};
} book2;
// 两者访问内部变量有不同
book1.price.dollars
book1.price.yen
book2.dollars
book2.yen
注意
作为共用体成员,它内部的 dollars 和 yen 成员共用同一块内存,我们可以给 price 设置为 dollars 也可以设置为 yen,但是不能同时设置两者。
枚举类型 - Enumerated types (enum)
枚举类型是自定义的一组标识(成为枚举器),枚举类型的对象可以设置为任何枚举器的值。语法如下
enum type_name {
value1,
value2,
value3,
.
.
} object_names;
例如
enum months_t { january=1, february, march, april,
may, june, july, august,
september, october, november, december} y2k;
其中枚举变量 y2k 拥有12个可能的值。从第一个值手动赋值为1, 后面的值累加。
每个枚举器都和用户赋的值可以进行隐式转换,即 january 与 1 可以互转。
C++ 中的真正枚举类型
C++ 中可以定义真正枚举类型: 每个枚举器没有对应的int 值,也不可以进行隐式转换。从而保证了枚举类型的安全性。
定义方式为 enum class (or enum struct) 代替仅仅的 enum;
enum class Colors {black, blue, green, cyan, red, purple, yellow, white};
使用方式: 对于枚举器必须包装到自己的类型内(但 enum 也可以这样用,但是可选)
Colors mycolor;
mycolor = Colors::blue;
if (mycolor == Colors::green) mycolor = Colors::red;
可以限定枚举器类型和占用空间,方式为添加冒号 和 类型。如下:定义了 Eyecolor
为只有一个字节 char 类型(1个字节)。
enum class EyeColor : char {blue, green, brown};
网友评论