inline, const, virtual, static四个关键字使用时应该放在哪里?

本文详细介绍了C++中inline, const, virtual, static四个关键字在声明和定义时的位置要求,以及它们在类声明、成员函数、静态成员等场景中的应用和规范。强调了inline函数的编译时展开特性,const关键字在声明和定义处的必要性,virtual关键字只应用于类成员函数的声明,并讨论了static成员函数和数据成员的声明、定义和初始化规则。" 139143841,9247363,Git进阶:深度解析git rebase与git fetch,"['git', '版本控制', '代码管理']

注意,下面说的“声明”指的是非定义处的声明,别跟我扯什么“所有的定义都是声明”什么的。

1. inline
inline可以放在声明处,也可以放在定义处,也可以两个地方都放。但是inline是属于实现部分的内容,不应该出现在接口处,即类的使用者从使用的角度不需要知道是不是inline的。所以,编程规范是inline关键字应该只出现在定义处,而不应该在声明处,所以class body里不应该出现“inline”。这一点在C++ FAQ(http://www.parashift.com/c++-faq/)[9] Inline functions中有提到。BTW,所有在class body中实现的函数都是隐含inline的,因而在class body里实现的短函数也不需要显式的写上“inline”。所以可以得出结论:任何情况下都不应该在class body里看到“inline”这个关键字(注释除外)。新手也许会问,如果我在a.cc里定义了一个inline函数fun(),在b.cc里forward declare并使用了fun。按照编程规范,b.cc中对fun()的declaration处不标inline,那b.cc中使用fun()时,编译器怎么知道该把fun()内联展开呢?答案是inline函数不能像普通函数那样在另一文件中forward declare后调用,使用inline函数的唯一方法就是include(直接或间接)其定义,所以在定义处标inline就够了。

定义类的时候,如果inline member function的实现较短,可以和class body放在一个.h文件里;如果实现较长,则不应该和class body堆在一起,可以单列一个-inl.h文件存放inline函数的定义。注意:inline函数为了能够在编译时展开(即被inlined),所有使用该inline函数的地方都需要它的定义。所以inline函数的定义是放在.h文件中的,而不是像非inline成员函数放在.cc/.cpp文件

<think>我们首先需要整理C++11、C++14、C++17、C++20和C++23(截至当前)中新增的关键字,以及旧关键字的新含义。注意,C++23可能还在发展中,我们以已发布的标准为准。新增关键字:-C++11:alignas,alignof,char16_t,char32_t,constexpr,decltype,noexcept,nullptr,static_assert,thread_local,auto(新含义),using(新含义:类型别名)等。注意:auto和using在C++11之前存在,但C++11赋予了它们新的含义或用法。-C++14:新增关键字较少,主要是对C++11的扩展,没有特别新增的关键字。但可能有新增的含义,比如泛型lambda。-C++17:alignas,alignof,auto,bool,break,case,catch,char,char16_t,char32_t,class,const,constexpr,const_cast,continue,decltype,default,delete,do,double,dynamic_cast,else,enum,explicit,export,extern,false,float,for,friend,goto,if,inline,int,long,mutable,namespace,new,noexcept,nullptr,operator,private,protected,public,register,reinterpret_cast,return,short,signed,sizeof,static,static_assert,static_cast,struct,switch,template,this,thread_local,throw,true,try,typedef,typeid,typename,union,unsigned,using,virtual,void,volatile,wchar_t,while(这些是C++17保留关键字,但新增的关键字有:co_await,co_return,co_yield(用于协程),但协程是TS,在C++20才正式加入;实际上C++17新增的关键字有:inline(用于变量)的新含义,以及可能引入的__has_include预处理常量(但不是关键字)。严格来说,C++17新增的关键字是:co_await,co_yield,co_return(协程相关),但协程在C++20才标准化,所以通常认为C++17没有新增关键字,而是增加了结构化绑定的语法(但不需要新关键字)。另外,C++17引入了`__has_include`预处理标识符,但不是关键字。实际上,根据标准文档,C++17新增的关键字是`co_await`,`co_yield`,`co_return`(用于协程),但是协程特性在C++17中并没有完全标准化,而是作为技术规范(TS)存在,直到C++20才正式加入。因此,在C++17中,这些关键字可能不被视为核心语言的一部分。所以,通常认为C++17没有新增关键字,而是增加了新的语法形式(如结构化绑定,使用`auto`等已有关键字)。-C++20:新增关键字:concept,requires,constinit,consteval,co_await,co_yield,co_return,char8_t,import,module。其中`co_await`,`co_yield`,`co_return`是协程相关,`concept`和`requires`用于概念,`constinit`和`consteval`用于常量初始化,`char8_t`用于UTF-8字符,`import`和`module`用于模块。-C++23:目前已经确定新增的关键字:...(需要查阅,但根据当前进展,可能包括:`char8_t`(已在C++20引入)的进一步支持,以及可能的新关键字如`dyn`(动态分配)?实际上,C++23新增的关键字有:`constexpr`(扩展),但没有全新的关键字?根据最新资料,C++23新增了`constexpr`在if语句中的使用,但没有引入全新的关键字。不过,我们以最终标准为准。目前已知C++23没有引入全新的关键字,而是引入了新的运算符`<=>`(但这不是关键字)。因此,我们主要关注C++11、C++14(无新增)、C++17(通常认为无新增关键字,但协程关键字在C++20才正式加入)、C++20。另外,旧关键字的新含义:-auto:在C++11之前用于指定自动存储类型(几乎不用),在C++11中用于自动类型推导。-using:在C++11之前用于引入命名空间和基类成员,在C++11中增加了类型别名的功能(替代typedef)。-register:在C++11中被弃用,在C++17中被移除(但移除的是关键字的功能,关键字本身可能保留为无用?实际上,在C++17中,register关键字被移除了,不再是关键字)。-inline:在C++17之前用于函数内联,在C++17中增加了内联变量的含义。我们按照标准版本整理表格。注意:由于C++14没有新增关键字,我们只列出C++11、C++17(如果有)、C++20、C++23(如果有)。对于C++17,虽然协程关键字在C++20正式加入,但为了清晰,我们可以在C++20中列出协程关键字。同,C++17中新增的含义(如inline变量)我们列在C++17的旧关键字新含义中。表格设计:|标准版本|新增关键字|旧关键字新含义|使用场景|示例代码||----------|-----------|---------------|---------|---------||C++11|...|...|...|...||C++14|(无)|(无)|(无)|(无)||C++17|(无)|inline|内联变量|...||C++20|...|...|...|...||C++23|(无)|(无)|(无)|(无)|但是,实际上C++14还是有一些小的扩展,比如泛型lambda,但不需要新关键字。同样,C++17的结构化绑定也不需要新关键字。下面详细列出:C++11新增关键字:-alignas:指定对齐要求。-alignof:获取对齐要求。-char16_t:用于UTF-16的字符类型。-char32_t:用于UTF-32的字符类型。-constexpr:常量表达式,表示在编译求值的表达式。-decltype:获取表达式的类型。-noexcept:指定函数不会抛出异常。-nullptr:空指针常量。-static_assert:编译断言。-thread_local:线程局部存储。同,C++11中旧关键字的新含义:-auto:自动类型推导。-using:用于类型别名(类似于typedef,但更强大)。C++17:新增关键字:无(协程关键字在C++20标准化)旧关键字新含义:-inline:用于变量,表示变量在多个翻译单元中定义,链接器会合并为一个实例(用于头文件中的变量定义)。C++20:新增关键字:-char8_t:用于UTF-8字符(与unsignedchar不同)。-concept:定义概念(用于模板约束)。-consteval:指定立即函数(必须在编译求值)。-constinit:指定常量初始化(但非常量)。-co_await:协程中挂起点。-co_yield:协程中产生值。-co_return:协程中返回。-requires:用于指定模板约束或检查约束。-import:导入模块。-module:定义模块。旧关键字新含义:无(或者有扩展,如constexpr函数中可以包含更多语句,但关键字含义没有改变)C++23:目前没有新增关键字,也没有旧关键字的新含义(但有一些扩展,比如constexpr扩展,ifconstexpr允许更多形式等,但关键字本身含义未变)。另外,注意C++11中还有一些关键字的新用法,比如final和override(但它们不是新增的关键字,在C++11之前这些词不是关键字,在C++11中成为具有特殊含义的标识符?实际上,它们是作为上下文相关的关键字引入的,即它们只在特定位置(类中)作为关键字,其他位置可以用作标识符。严格来说,它们是新增的关键字,但只用在特定上下文。因此,我们也应该列出。所以,补充C++11新增的关键字:final,override。因此,调整C++11新增关键字:-alignas,alignof,char16_t,char32_t,constexpr,decltype,noexcept,nullptr,static_assert,thread_local,final,override.另外,C++11中新增了原始字符串字面量,但不需要新关键字。下面我们制作表格。注意,由于表格较大,我们分版本列出。使用场景和示例代码:C++11:-auto:自动类型推导,用于简化复杂类型的声明。示例:`autoi=42;//i为int`-using(类型别名):定义类型别名,比typedef更灵活。示例:`usingIntVector=std::vector<int>;`-final:禁止类被继承或虚函数被重写。示例:`classBasefinal{};`或`virtualvoidfoo()final;`-override:显式声明重写基类的虚函数。示例:`virtualvoidfoo()override;`其他新增关键字示例:-constexpr:编译常量或函数。`constexprintsquare(intx){returnx*x;}`-nullptr:空指针。`int*ptr=nullptr;`-thread_local:线程局部变量。`thread_localintcounter=0;`C++17:-inline(变量):允许在头文件中定义变量而不会导致链接错误。示例:`inlineintglobal=42;`C++20:-char8_t:用于UTF-8字符,避免与char的混淆。示例:`char8_tc=u8'a';`-concept:定义模板约束。示例:```cpptemplate<typenameT>conceptIntegral=std::is_integral_v<T>;```-requires:使用概念约束模板参数。示例:```cpptemplate<IntegralT>Tadd(Ta,Tb){returna+b;}```或```cpptemplate<typenameT>requiresIntegral<T>Tadd(Ta,Tb){returna+b;}```-constinit:确保变量静态初始化(但不一定是常量)。示例:`constinitstaticintx=42;`-consteval:函数必须为常量表达式(立即函数)。示例:`constevalintadd(inta,intb){returna+b;}`-co_await,co_yield,co_return:协程。示例(简单协程):```cpp#include<coroutine>structgenerator{structpromise_type{intcurrent_value;autoget_return_object(){returngenerator{this};}autoinitial_suspend(){returnstd::suspend_always{};}autofinal_suspend()noexcept{returnstd::suspend_always{};}voidreturn_void(){}voidunhandled_exception(){std::terminate();}autoyield_value(intvalue){current_value=value;returnstd::suspend_always{};}};//...省略实现细节};generatormy_coroutine(){co_yield1;co_yield2;co_return;}```-import,module:模块。示例:```cpp//module.ixxexportmodulemymodule;exportvoidhello();//实现module:private;voidhello(){...}``````cpp//main.cppimportmymodule;intmain(){hello();}```注意:由于表格中需要包含多个关键字,我们可能需要为每个版本的多行分别写使用场景和示例代码。因此,我们按每个关键字一行来制作表格(但这样表格会很长)。或者我们按版本分组,每个版本内分行列出每个关键字。我们这样设计:|标准版本|关键字|类型(新增/旧词新义)|使用场景|示例代码||----------|--------|----------------------|---------|---------||C++11|auto|旧词新义|...|...||C++11|using|旧词新义|...|...||...|...|...|...|...|这样更清晰,但行数会很多。考虑到用户要求的是每个标准新增的关键字和旧关键字的新含义,我们分开列出。我们决定按照版本分节,然后在每个版本内用表格列出该版本的关键字变化。由于Markdown中表格过长可能影响阅读,我们按版本分别制作表格。开始编写:注意:示例代码需要简短,并且符合C++语法。由于引用中提供了一些代码示例,但与我们所需的关键字示例不完全匹配,我们自行编写。下面开始输出:</think>以下是C++11及之后标准新增关键字、旧关键字新含义的详细总结表格,包含使用场景和示例代码: ### C++11及之后标准关键字变化总结 | 标准版本 | 关键字 | 类型 | 使用场景 | 示例代码 | |----------|----------------|------------|------------------------------------|--------------------------------------------------------------------------| | **C++11** | `alignas` | 新增 | 内存对齐控制 | `alignas(16) struct Vec3 { float x, y, z; };` | | | `alignof` | 新增 | 获取内存对齐值 | `alignof(Vec3) // 返回16` | | | `constexpr` | 新增 | 编译期常量计算 | `constexpr int sqr(int n) { return n*n; }` | | | `decltype` | 新增 | 表达式类型推导 | `decltype(x+y) z = x+y;` | | | `noexcept` | 新增 | 异常规范声明 | `void foo() noexcept;` | | | `nullptr` | 新增 | 空指针类型安全替代 | `int* ptr = nullptr;` | | | `thread_local` | 新增 | 线程局部存储 | `thread_local int counter = 0;` | | | `auto` | 旧词新义 | 自动类型推导 | `auto i = 42; // int` | | | `using` | 旧词新义 | 类型别名(替代typedef) | `using StringVector = std::vector<std::string>;` | | **C++14** | `auto` | 功能扩展 | lambda参数类型推导 | `auto lambda = [](auto x) { return x*2; };` | | | `constexpr` | 功能扩展 | 支持循环/局部变量 | `constexpr int factorial(int n) { int r=1; for(;n>0;n--)r*=n; return r;}`| | **C++17** | `inline` | 旧词新义 | 内联变量定义 | `inline int sharedVar = 100; // 头文件中定义` | | | `auto` | 功能扩展 | 结构化绑定 | `auto [id, name] = std::make_pair(1, "Alice");` | | **C++20** | `concept` | 新增 | 模板约束定义 | `concept Addable = requires(T a, T b) { {a+b} -> std::same_as<T>; };` | | | `requires` | 新增 | 约束检查/子句 | `template<Addable T> T add(T a, T b) { return a+b; }` | | | `co_await` | 新增 | 协程挂起 | `co_await async_op();` | | | `co_yield` | 新增 | 协程产出值 | `co_yield 42;` | | | `co_return` | 新增 | 协程返回 | `co_return result;` | | | `char8_t` | 新增 | UTF-8字符类型 | `char8_t utf8_char = u8'A';` | | | `consteval` | 新增 | 立即函数(强制编译期执行) | `consteval int sq(int n) { return n*n; }` | | | `constinit` | 新增 | 静态初始化(非常量) | `constinit static int x = init_func();` | ### 关键特性说明 1. **`constexpr`扩展** C++11引入基础编译期计算,C++14允许循环/局部变量,C++20支持虚函数和try-catch。 2. **协程关键字** `co_await`/`co_yield`/`co_return`构成异步编程基础,用于生成器、异步I/O等场景[^1]。 3. **概念约束(C++20)** `concept`和`requires`实现模板类型约束,替代SFINAE复杂技巧: ```cpp template<typename T> concept Printable = requires(T v) { { std::cout << v } -> std::same_as<std::ostream&>; }; void print(Printable auto const& val) { std::cout << val; } ``` 4. **结构化绑定(C++17)** 解包复合类型(元组/结构体): ```cpp std::map<int, std::string> m; auto [iter, success] = m.insert({1, "one"}); ``` 5. **模块系统(C++20)** 使用`import`/`module`替代头文件: ```cpp // math.ixx export module math; export int add(int a, int b) { return a+b; } // main.cpp import math; add(10,20); ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值