C++对const申明的扩展

Last Updated: 2023-12-24 06:14:59 Sunday

-- TOC --

由于C++兼容历久弥新的C,C语言中的const申明所支持的,C++显然都要支持。而C++引入了很多新的语法规则,对const申明也进行了扩展。

修饰成员函数

被const修饰的成员函数,被称为const method,或者read-only method,即他们只能读取对象的成员变量,不能修改。

struct ClockOfTheLongNow {
    --snip--
    int get_year() const {
        return year;
    }
    private:
        int year;
};

有两个术语,accessormutator,accessor就是有const修改的class method。

const接口是function signature的一部分!

修饰引用参数

引用,reference,是C++引入的一个新特性,它没有指针灵活,但比指针安全。常见一些成员函数接口参数,就是对象的引用。

bool is_leap_year(const ClockOfTheLongNow& clock) {
    if (clock.get_year() % 4 > 0) return false;
    if (clock.get_year() % 100 > 0) return true;
    if (clock.get_year() % 400 > 0) return false;
    return true;
}

在is_leap_year函数范围内,不允许出现没有const修饰的clock的成员函数接口。

由于get_year已经被申明为const,因此上面的测试代码,可以顺利编译通过。在is_leap_year的执行范围内,clock这个引用对象的状态(成员变量),不允许被修改,不管它们是否有自己的const申明。

修饰(成员)变量

在C++中,字符串常量的申明,必须使用const,否则会有warning:

struct Avout {
    const char* name = "Erasmas";
    const int a = 1;
};

如上定义的name变量,必须使用const,否则g++编译器会给出一个warnning。而gcc不会。这是体现出C++语法要求更严格!

如果希望const变量能够在对象初始化的时候,其值由传入的参数指定,这时,你需要使用C++的初始化列表const变量除了在定义的地方赋值,不能有其它显式地的赋值,如果是对象成员,还能通过初始化列表,仅此。

有个比较tricky的细节,对象初始化列表会覆盖已经赋值的const变量:

#include <iostream>
#include <string>
using namespace std;

struct xyz{
    const int a {1};
    xyz(int x): a{x} {}
};

int main(void) {
    xyz z{2};
    cout << z.a << endl;
    return 0;
}

输出2,原来定义的1被初始化列表覆盖了。我们可以这样来理解这个feature:const只是readonly,值可以是runtime确定的,确定后readonly,而runtime确定const值,就是在对象初始化的时候。

static成员变量的初始化

如果static成员变量没有const申明,那么这个static成员变量的初始化,只能在global scope下进行,具体请参考:C++ class中的static理解

但是有一个例外,就是static const,这类成员变量,就直接在申明的地方初始化。

class Apple 
{ 
    public: 
        // 被const修饰的static变量在c++11中可以在类内被直接初始化。
        const static int i {10}; 
};

我是这样理解的:被const修饰的变量,可以在编译期有可用的值,而被constexpr修饰的变量,必须在编译器有可用的值。也就是说,const包含了constexpr的意思。也因此,需要在编译期使用的变量,建议都是用constexpr。而const,基本都用于修饰函数接口的入参,以及作为function signature的一部分。

本文链接:https://cs.pynote.net/sf/c/cpp/202208101/

-- EOF --

-- MORE --