Wang's blog

类中的新特性

Published on

委托构造

同一个类中的一个构造函数可以调用另一个构造函数,从而达到简化代码的目的:

class Base
{
public:
    Base()
    {
        value1 = 1;
    }
    Base(int value) : Base() // 委托Base()构造函数
    {
        value2 = 2;
    }

private:
    int value1;
    int value2;
};

继承构造

假设父类有多个版本的构造函数,即使子类不进行修改,也必须编写同样多的构造函数,将参数透传至父类,例如:

class A
{
public:
    A(int i) {}
    A(double d, int i) {}
    A(float f, int i, const char *c) {}
    //......
};

class B : public A
{
public:
    B(int i) : A(i) {}
    B(double d, int i) : A(d, i) {}
    B(float f, int i, const char *c) : A(f, i, c) {}
    //......
};

在C++11以后,使用继承构造可以避免编写此类重复代码:

class A
{
public:
    A(int i) {}
    A(double d, int i) {}
    A(float f, int i, const char *c) {}
    //......
};

class B : public A
{
    using A::A; // 使用继承构造
};

final与override

final关键字可修饰一个类,以禁止该类被继承;也可修饰一个虚函数,以禁止该函数被子类重写:

class Base final
{
};

// 错误,Base不能被继承
class Derived : public Base
{
};

class Base
{
    virtual void func() final
    {
        std::cout << "base" << std::endl;
    }
};

class Derived : public Base
{
    // 错误,func不能被重写
    void func() override
    {
        std::cout << "derived" << std::endl;
    }
};

与final相反,当使用override关键字修饰一个函数时,此函数必须重写父类的虚函数,如果父类没有该虚函数则会报错:

class Base
{
    virtual void func()
    {
        std::cout << "base" << std::endl;
    }
};

class Derived : public Base
{
    // 确保func()重写虚函数
    void func() override
    {
        std::cout << "derived" << std::endl;
    }

    // 错误,父类没有fu()函数,不可以重写
    void fu() override
    {
    }
};

delete与default

C++编译器有时会自动生成一些默认函数。例如,如果用户没有为一个类声明任何构造函数,则编译器会生成一个默认构造函数:

class A
{
};

A a;    // 由于存在默认构造函数,此行代码可运行

如果想要禁止编译器生成默认函数,可使用delete关键字:

class A
{
    A() = delete;
};

A a;    // 由于删除了默认构造函数,此行代码不可运行

某些情况下,用户没有编写某个函数,编译器也没有生成默认版本。例如,当用户为一个类声明任意一个构造函数后,编译器不会生成默认构造函数:

class A
{
public:
    A(int i) {}
};

A a;    // 未生成默认构造函数,此行代码不可运行

此时,如果需要默认版本的函数,可使用default关键字要求编译器生成:

class A
{
public:
    A() = default;
    A(int i) {}
};

A a;    // 生成了默认构造函数,此行代码可运行

explicit

explicit用于修饰构造函数,表示只能显式构造,不可以被隐式转换。

class A
{
public:
    // 未使用explicit关键字
    A(int value)
    {
        std::cout << "value" << std::endl;
    }
};

A a = 1;    // 可以隐式转换

class A
{
public:
    // 使用了explicit关键字
    explicit A(int value)
    {
        std::cout << "value" << std::endl;
    }
};

A a = 1;    // 错误,不可以隐式转换
A aa(2);    // 正确,显式调用构造函数