小白学习大型C++源码项目系列之枚举类(enum class或是enum struct)

枚举:是被命名的整型常数的集合,通过对整型类型的重命名,可以更加直观的表达。

结构体的理解

使用结构体(Struct)来存储相同类型或不同类型数据的集合。
结构体也是一种数据类型,它由程序员自己定义,可以包含多个其他类型的数据。
像 int、float、char 等是由C语言本身提供的数据类型,不能再进行分拆,我们称之为基本数据类型;而结构体可以包含多个基本类型的数据,也可以包含其他的结构体,我们将它称为复杂数据类型或构造数据类型。

结构体的两种常见分类

标准结构体:标准情况“struct 结构体名 { 数据类型…… }结构体变量名;”
匿名结构体:锁定变量变量个数“struct { 数据类型…… }结构体变量名;”即没有结构体名

先定义结构体类型,在定义变量

struct stu 
{ //定义一个结构体,这种数据类型是 “struct stu”;
	char *name; //姓名
	int num; //学号
	int age; //年龄
	char group; //所在学习小组
	float score; //成绩
};

struct stu stu1, stu2; //stu1、stu2就是结构体变量;

定义了两个变量 stu1 和 stu2,它们都是 stu 类型,都由 5 个成员组成。
注意关键字struct不能少。stu 就像一个“模板”,定义出来的变量都具有相同的性质。

结构体变量的引用方式

1) 结构体变量名.成员名:stu1.name
2) 结构体指针变量->成员名:ps -> name

3) (*结构体指针变量).成员名:(*ps).name 因为优先级的问题,所以要加括号
4) 结构体变量数组名.成员名:stu[0].name

我项目中的用法

struct Config
{
    bool is_table_test_ = false;
};
// 定义一个结构体变量
Config config_;

结构体作为函数的返回值

原来结构体可以作为函数的参数,也可以作为函数的返回值。
这么用属于函数的传值调用,函数中使用的是结构体的副本,函数中的操作不会改变原结构体的值,但是会牺牲一些速度。
用指针传递结构体变量的话,属于传址调用,是直接操作结构体,所以函数中的操作直接反应到结构体上。
OpenCV中这么做,一是结构体比较小,影响内存开销比较小;二是防止改变结构体本身吧。一点浅见。

#include<stdio.h>
//定义一个结构体
typedef struct Point
{
       int x;
       int y;
}Point;

//使用一个结构体变量作为函数的参数
void Display(Point point)
{
       printf("x is %d\n",point.x);
       printf("y is %d\n",point.y);
       /*********若使用C++,则如下*************
       std::cout<<"x is "<<point.x<<std::endl;
       std::cout<<"y is "<<point.y<<std::endl;
       **************************************/
}

//使用结构体变量作为函数的返回值
Point SetPoint(int x,int y)
{
       Point point;
       point.x=x;
       point.y=y;
       return point;
}

//主函数
int main(int atgc,char * argv[])
{
       Point point;
       point=SetPoint(2,3);
       Display(point);
       return 0;
}

运行结果

x is 2
y is 3

const 用于修饰“返回引用”函数的返回值

如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。
例如把函数int GetInt(void) 写成const int GetInt(void)是没有意义的。

如果返回值不是内部数据类型,将函数MyClass GetObj(void) 改写为const Myclass & GetObj(void)的确能提高效率。
但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。

这里对函数返回值使用 const 的目的在于限制不能将函数调用表达式作为左值使用。例如有如下函数:

int & min ( int &i, int &j);

可以对函数调用进行赋值,因为它返回的是左值: min ( a , b )=4;

但是,如果对函数的返回值限定为 const 的,即丁奕:const int & min ( int & i, int &j );

那么,就不能对 min ( a, b ) 调用进行赋值了。

事实上,函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。

class A
{
A &amp; operate = (const A &amp; other); // 赋值函数
} ;
A a, b, c; // a, b, c 为A 的对象
a = b = c; // 正常的链式赋值
(a = b) = c; // 不正常的链式赋值,但合法

如果将赋值函数的返回值加const 修饰,那么该返回值的内容不允许被改动。
上例中,语句 a = b = c 仍然正确,但是语句 (a = b) = c 则是非法的。

枚举类

有的时候一个类的对象是有限且固定的,这种情况下我们使用枚举类就比较方便。

将enum封装到类的内部,enum class 和 enum struct 是等价的。

枚举体的声明和定义使用 enum class或是enum struct, 二者是等价的。
使用enum class\enum struct不会与现存的enum关键词冲突。
而且enum class\enum struct具有更好的类型安全和类似封装的特性(scoped nature)。

enum class color{red,green,yellow}; 
enum class colorx{red,green=100,yellow}; 

用enum定义的枚举体是一个不具有封装性(不知道如何翻译是好:unscoped enumeration)的枚举体,他的成员可以在enum的大括号外被直接访问。而用enum class或是enum struct(二者在语法上是等价的)定义的枚举体是具有封装性的(scoped enumeration),他的成员同过成员名直接访问,而应通过域运算符来访问。

   #include <iostream>
     
    enum class color{red,black};
    enum colorx{green,yellow};
     
    int main() {
        color::red;//用域运算符访问color的成员
        green;//直接访问colorx的成员
        colorx::green;//用域运算符访问colorx的成员
        std::cin.get();
        return 0;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章