《C++11/14高级编程Boost程序库探秘》之第1章全新的C++语言(二)学习记录

《C++11/14高级编程Boost程序库探秘》之第1章全新的C++语言(二)

1.4面向过程编程

1.4.1空指针

nullptr明确表示空指针概念,可以完全替代NULL,它可以隐式转化为任意类型的指针,也可以与指针进行比较运算,但决不能转化为非指针的其他类型。比如,10>=nullptr会提示编译错误,不能与整数等类型进行运算。

在编写代码时,应总使用nullptr来初始化或比较指针,尽量避免使用NULL宏。

1.4.3新式for循环

[root@localhost C++11]# cat newfor.cpp
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    int a[] = {2,3,5,7};
    vector<int> v = {253,874};

    for(auto x : a)  //使用auto推导类型变量
    {
        cout<<x<<",";  //直接访问元素,无须解引用
    }

    for(const auto& x : v)
    {
        cout<<x<<",";
    }
    return 0;
}
[root@localhost C++11]# g++ newfor.cpp -o newfor -std=c++11
[root@localhost C++11]# ./newfor
2,3,5,7,253,874,

1.4.4 新式函数声明

允许返回值类型后置,格式如下:

auto func(...) -> type {...}

首先,函数返回值处必须使用auto来占位;

其次,函数名后需要使用->type的形式来声明真正的返回值类型。

之所以采用这种方式是因为在泛型编程的时候,函数返回值的类型可能需要由实际的参数来决定,所以需要将返回值类型的声明延后。

1.5面向对象编程

1.5.1 default

允许显示地声明类的缺省构造/析构等特殊成员函数,不仅能够明确地表示代码意图,而且可以让编译器更好地优化代码。

class default_demo

{

public:

//显示指定构造函数和析构函数使用编译器的缺省实现

    default_demo()  =default;

    ~default_demo() =default;

//显示指定拷贝构造函数和拷贝赋值函数使用编译器的缺省实现

    default_demo(const default_demo&)  =defualt;

    default_demo& operator=(const default_demo&)   =default;

//显示指定转移构造函数和转移赋值函数使用编译器的缺省实现

    default_demo(default_demo&&)  =default;

    default_demo& operator=(default_demo&&)   =default;

}

1.5.2 delete

显示的禁用某些函数——通常是类的构造函数和拷贝构造函数,以阻止对象的拷贝。

[root@localhost C++11]# cat deletedemo.cpp
#include <iostream>
#include <vector>
using namespace std;

class delete_demo
{
public:
    delete_demo() =default;
    ~delete_demo() = default;

    //显示禁用拷贝构造函数和拷贝赋值函数
    delete_demo(const delete_demo&) =delete;
    delete_demo& operator=(const delete_demo&) = delete;
}

int main()
{
    delete_demo d1;
    delete_demo d2 = d1;//无法赋值,发生编译错误
    return 0;
}
delete不仅可以作用于类成员函数,也可以作用于普通函数,禁用某些形式的重载。

1.5.3 override

显式地标记虚函数的重载,派生类里的成员函数名后如果使用了override修饰,那么它必须是虚函数,而且签名也必须与基类的声明一致,否则会导致编译错误。

[root@localhost C++11]# cat overridedemo.cpp
#include <iostream>
#include <memory>
using namespace std;

class base
{
public:
    virtual ~base() = default;
    virtual void f() = 0;//纯虚函数
    virtual void g() const {    cout<<"base:g func"<<"\n"<<endl;    };//虚函数,const修饰
    void h(){    cout<<"base:h func"<<"\n"<<endl;    };
};

class derived : public base
{
public:
    virtual ~derived() = default;
    void f() {    cout<<"derived:f func"<<"\n"<<endl;    }//虚函数重载
    void g() {    cout<<"derived:g func"<<"\n"<<endl;    }//不是虚函数重载,签名不同,无const修饰
    void h() {    cout<<"derived:h func"<<"\n"<<endl;    }//不是虚函数重载,是覆盖
};

int main()
{
    unique_ptr<base> p(new derived);
    p->f();
    p->g();//调用了基类的g函数,与初衷不符
    p->h();//调用了基类的h函数,与初衷不符
    return 0;
}
[root@localhost C++11]# g++ overridedemo.cpp -o overridedemo -std=c++11
[root@localhost C++11]# ./overridedemo
derived:f func
base:g func
base:h func
使用override后,代码修改如下:

[root@localhost C++11]# cat overridedemo_new.cpp
#include <iostream>
#include <memory>
using namespace std;

class base
{
public:
    virtual ~base() = default;
    virtual void f() = 0;//纯虚函数
    virtual void g() const {    cout<<"base:g func"<<"\n"<<endl;    };//虚函数,const修饰
    void h(){    cout<<"base:h func"<<"\n"<<endl;    };
};

class derived : public base
{
public:
    virtual ~derived() = default;
    void f() override {    cout<<"derived:f func"<<"\n"<<endl;    }//override明确是虚函数重载
    void g() const override {    cout<<"derived:g func"<<"\n"<<endl;    }//有const修饰,override明确是虚函数重载
    void h() override {    cout<<"derived:h func"<<"\n"<<endl;    }//非虚函数重载,调用override,编译报错
};

int main()
{
    unique_ptr<base> p(new derived);
    p->f();
    p->g();
    p->h();
    return 0;
}
[root@localhost C++11]# g++ overridedemo_new.cpp -o overridedemo_new -std=c++11
overridedemo_new.cpp:20:10: error: ‘void derived::h()’ marked ‘override’, but does not override
   20 |     void h() override {    cout<<"derived:h func"<<"\n"<<endl;    }//非虚函数重载,调用override,编译报错
      |          ^
1.5.4 final

在类名后使用final,显式地禁止类被继承,即不能再右派生类。

在虚函数后使用final,显式地禁止该函数在子类里再被重载。

final和override混用,更好的标记类的继承体系和虚函数。

[root@localhost C++11]# cat finaldemo.cpp
#include <iostream>
#include <memory>
using namespace std;

class base
{
public:
    virtual ~base() = default;
    virtual void f() = 0;//纯虚函数
    virtual void g() = 0;//纯虚函数
};

class derived : public base
{
public:
    virtual ~derived() = default;
    void f() override final {    cout<<"derived:f func"<<"\n"<<endl;    }//虚函数重载,使用final,不能再被重载
    void g() override {    cout<<"derived:g func"<<"\n"<<endl;    }//虚函数重载,派生类还可以继续重载
};

class child final : public derived
{
public:
    void f() override {}//错误,f()不可再被重载
    void g() override {}//g仍然可以被重载
};

class end : public child //错误,child类不能被继承
{
};

int main()
{
    return 0;
}
[root@localhost C++11]# g++ finaldemo.cpp -o finaldemo -std=c++11
finaldemo.cpp:24:10: error: virtual function ‘virtual void child::f()’ overriding final function
   24 |     void f() override {}//错误,f()不可再被重载
      |          ^
finaldemo.cpp:17:10: note: overridden function is ‘virtual void derived::f()’
   17 |     void f() override final {    cout<<"derived:f func"<<"\n"<<endl;    }//虚函数重载,使用final,不能再被重载
      |          ^
finaldemo.cpp:28:7: error: cannot derive from ‘final’ base ‘child’ in derived type ‘end’
   28 | class end : public child //错误,child类不能被继承
1.6 泛型编程

1.6.1 类型别名

使用using alias = type的形式为类型起别名,例如:

using int64 = long;

using llong = long long;

1.6.2 编译器常量

constexpr int kk = 1024;

constexpr long giga()//编译期常量函数

{    return 1000*1000*1000;}

1.6.3 静态断言

C语言提供assert,但泛型编程主要工作在编译期,assert无法起作用。

C++11/14增加了关键字static_assert,是编译期断言,基本用法是

static_assert(condition,message)

如果condition表达式在编译期的计算结果为false,那么编译期会报错,并给出message提示。

1.6.4 可变参数模板

可变参数模板使用省略号...来声明不确定数量的参数,形式如下:
template<typename ... T> class some_class {};//模板类

template<typename ... T>void some_fun() {};//模板函数

模板参数列表里的typename ... T声明了一个具有不确定数量参数的模板列表——模板参数包,其数量可以是0,1或者更多,可以使用sizeof...(T)的方式得到具体数量。

声明了可变模板参数后,还需要解开包才能使用,直接在类型名后用...即可,例如:

template<typename ... T>

class variadic_class

{

    using type = x<T...>;

};

template<typename ... Args>

void variadic_func(Args ... args)

{    cout<<sizeof...(Args)<<endl;}

猜你喜欢

转载自www.cnblogs.com/snake-fly/p/12614099.html