自定义类型

c++语言分两部分,语言核心和标准库
c++已经为我们提供了一些基本类型,我们可以通过这些基本类型构建复杂的类型
c++提供的内置类型和操作非常丰富,也很low-level(基本:直接、高效,这些操作反应了计算机常规能力)
利用这些内置类型和操作 + 抽象机制 = everything

抽象机制是为了让程序员设计和实现自定义的类型(有合适的表示和操作),并且可以非常简单非常优雅地使用这个类型。除了内置类型之外,利用抽象机制创建的类型称为用户自定义类型。简称类、枚举

大部分c++书籍都是告诉阅读者 如何设计 实现 使用 自定义类型

结构 struct

构建自定义类型的第一步
将几个类型丢在一个数据结构:struct
访问一个struct的元素用. dot 或是->

类 class

第二步
为几个数据增加几个操作,这样的优势是:可以通过任意方式使用数据
对于自定义类型来说 有一套严格联系存在于表现和操作中,这是为了让这个自定义类型拥有更多的属性,让她看起来像一个真正的实在的类型。对于用户来说(这里的用户指使用这个类型的程序员),我们希望用户不能访问表现(这里以及上面的表现就是类的具体实现),而是使用类型,这里的解释是:一个类型有接口和实现,接口(对应上面的“操作”)被用户使用,实现是类型提供者的工作,对应上面的表现。这样的语言机制称为class。一个类应该有一些成员(数据 函数 或者是类型成员);接口部分应该是public成员,private成员应该只能被接口访问。
如果一个成员函数的名称和类名一样,这个函数就被称为构造函数,这个构造函数用来初始化这个类型的对象,这样我们就不用担心类型中变量未初始化的问题。

联合 unions

unions是一种特殊的struct,她的所有的成员都放在同一个内存中,大小是所有元素中最大的那个,每一次 unions只保存一个成员的数据

在c++中的某些特殊场景下使用unions是非常好的选择,首选需要说明 unions使用的场景:节约空间。这是c++之父的原话:“space is wasted”所以针对这种情况应优先使用unions。使用的时候极容易出错,所以最好将unions封装一下,若非要使用裸的unions,里面的成员也应当尽量简单
如何封装:

unions MyType{
    char* s;
    int i;
}

struct MyType2{
    Type t;
    MyType v;
}
// ps:假如 当t为一个值时v应取s;当t为另一个值时v应取i

// 为了保证每次都取到正确的值,在操作的时候应该特别注意:
void fun(MyType2* p){
    if (p->t == xx)
        p->v.s
    else if (p->t == xxx)
        p->v.i
}
// 如果是要封装,最好如上面一样 弄一个变量t来确保每次的对应关系是正确的

枚举 enum

除了class外,c++提供了一种简单的枚举值的自定义类型:enum

什么是enum?(或者说有啥规则)
enum里包含了一组值,这些值可以转换成int类型
需要注意的是:可能每个值都可能一样

先来看看enum的语法:
enum-key attr(optional) identifier(optional) enum-base(optional) { enumerator-list(optional) } (1)
enum-key attr(optional) nested-name-specifier(optional) identifier enum-base(optional) ; (2) (since C++11)

好吧,第一种是我们常见的写法;第二种是新标准加入的,是一种不透明的声明?啥意思:就是只定义了enum类型,然而并没有枚举值

具体分析一下上面的语法:
enum-key:三种可选值:enum、enum class 、enum struct,我们一般使用的是第一种, 后两种是新标准加的
attr:可选的,任意属性的序列
identifier:可选的,枚举类型的名称
enum-base:指定枚举值的类型,这个类型应该是可以和int兼容的,eg:long short longlong,如果不指定显示,默认就是int,形式如 enum abc:long{a,b};
enumerator-list:枚举值列表

语法简单介绍了一下,接下来介绍两种不同的枚举:
在介绍之前,先了解一下以前enum的不足(如果没有不足,也不会有新标准中添加的东西了)
“类型是int;可见范围:整个enum声明的作用域(容易造成命名冲突);不支持前置声明”
新标准将enum分成了两种不同的枚举:带范围限定的枚举和不带范围限定的枚举。
还是用英文描述准确一些:

unscoped enumeration
当语法中的enum-key指定为enum时就是这类了
enum name { enumerator = constexpr , enumerator = constexpr , … } (1)
enum name : type { enumerator = constexpr , enumerator = constexpr , … } (2) (since C++11)
enum name : type ; (3) (since C++11)
第一种情况就是我们以前常用的,
第二种是限定了类型
第三种是前置声明且指定了类型

scoped enumerations
当语法中的enum-key指定为enum class 或是enum struct时就是这类了
enum struct|class name { enumerator = constexpr , enumerator = constexpr , … } (1)
enum struct|class name : type { enumerator = constexpr , enumerator = constexpr , … } (2)
enum struct|class name ; (3)
enum struct|class name : type ; (4)
第一种是带范围限定的
第二中带类型
第三第四是前置声明

新标准c++17让我们可以为enum添加一个初始化列表
使用初始化列表需要满足以下几个条件:
the initialization is direct-list-initialization
the initializer list has only a single element
the enumeration is either scoped or unscoped with underlying type fixed
the conversion is non-narrowing

enum byte : unsigned char {}; // byte is a new integer type
byte b { 42 }; // OK as of C++17 (direct-list-initialization)
byte c = { 42 }; // error
byte d = byte{ 42 }; // OK as of C++17; same value as b
byte e { -1 }; // error

struct A { byte b; };
A a1 = { { 42 } }; // error
A a2 = { byte{ 42 } }; // OK as of C++17

void f(byte);
f({ 42 }); // error

enum class Handle : std::uint32_t { Invalid = 0 };
Handle h { 42 }; // OK as of C++17

对于新标准之后的枚举来说:
可以限定范围、可以指定类型、可以用初始化列表
默认情况下,enum class 只有 赋值 初始化 比较操作,作为自定义类型的一种,我们可以为枚举添加自己的操作:
eg:

enum class abc{
    a,
    b,
    c
};

abc& operator++(abc& t){
    switch (t) {
    case abc::a: return t = b;
    case abc::b: return t = c;
    case abc::c: return t = a;  
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值