C++存储修饰符解释

本文主要介绍C++存储修饰符,其能告知编译器标识符的生存周期、可见性及存储方式。还阐述了链接的概念,C++中链接分internal、external、no linkage三类。同时说明了标识符生存空间与可见性的关系,生存空间有四类,可见性与链接有关。

C++存储修饰符解释(纯理论部分)

在C++中,存储空间主要是指变量或者函数或者类(下文中为了方便都称为标识符)的可见性和使用范围。为此C++提供下面几个存储空间修饰(storageclassspecifiers),这些修饰符告诉编译器标识符的生存周期和可见性(可以理解为可引用性),以及这些标识符是应该如何被存储。

生存空间修饰符:
auto
register
static
extern
本文分成几个部分,每一个部分相对独立。

//////////////////////////////////////
//         链接(Linkage)         //
//////////////////////////////////////

[重要]定义一个标识符是如何被引用的

这里我首先解释一下链接的概念。这个概念对于我们理解本文中的一些其他的概念有着很重要的影响作用。链接是指声明在不同生存空间的标识符或者是在同一个生存空间中声明多次的标识符实际上都指向一个共同的内存空间(比如变量或者函数)。链接(Linkage)定义了一个标识符在程序中不同部分的是否可以引用(也就是是否"可见")。

c++中链接可以分成三类:
internal,
external,
以及
no linkage.

///////////////////////////
//  Internal Linkage
///////////////////////////

在文件生存空间(file
scope)中用static存储修饰符来声明标识符(变量或者函数)的话,
我们就说这个标识符是internal linkage。
否则的话,我们则说这个标识符是external linkage。

///////////////////////////
//  External Linkage
///////////////////////////

在文件生存空间(file
scope)中用我们没有使用任何存储修饰符来声明标识符(变量或者函数)的话,
我们就说这个标识符是external
linkage。虽然来讲我们应该显式使用存储修饰符extern来声明external linkage
标志符的,但是因为默认的情况就是external
linkage,所以我们可以不显式的提供extern修饰符。


///////////////////////////
//  No Linkage
///////////////////////////


如果标识符声明在一个区块(block)中,同时又没有extern 存储修饰符修饰,
我们就说这个标识符是no linkage,同时这个标识符只对这个区块是可见的。

////////////////////////////////////////
//         生存空间与可见性           //
//       (Scope and Visibility )    //
////////////////////////////////////////

[重要]定义变量在放在程序文件的那个部分

在进行下面的内容之前我先讲个实际上存在的现象。浩瀚的宇宙对于我们每个人来说都是那样的神秘,我们可以说那些东西对于我们生存在地球上人都是共有的,哈哈。至少我们在心里可以这样认为的。因为物体客观的存在在那里,不属于任何个人和团体的。但是我们说这些话有意义吗?其实一点意义都没有,只是我讲的一个现象而已拉。哈哈好下面把这个话题再拓展一下,对于浩瀚宇宙中的物体虽然不属于任何个人和团体,但是是每个人都可以取用吗?一个很简单的例子你去过月球吗?没有吧!!但是有些人却去过的,因为他们有着更好的工具条件(可以认为他们有更高的权限)。好拉,说现象就说到这里,

下面正式开始我们的话题。

标识符的"可见性"决定了我们可以在程序的哪些部分可以引用。当你的代码处于标识符生存空间的范围内,你可以引用标识符,否则你不可能引用到标识符。生存空间可以大概分成四类:
function scope,file scope,block scope和function prototype scope;

下面逐个解释一下生存空间与标识符可见性的关系:

※File scope
file scope标识符经常也被称“global” 或者
“external”标识符。标识符生存周期是从标识符
定义或者声明点开始一直到文件结束。
※Function scope
※Block scope
※Function-prototype scope
这三种生存空间很相似,这里不在表述。

这样我要用到我讲的那个现象了,因为出现了紧急状况。
生存空间只是可见性的必要条件但是绝对不是充分条件,现在开始分析一下file scope中涉及到的具体问题。我们是标识符是file scope是否意味着在程序中任何地方都可以引用标识符呢,实践的证明不是这样的,那现在弄清楚原因就是我们的目标。不错,在filescope中声名或者定义的标识符是"global"或者是"external"的,这个这是意味着这些标识符编译时候会被放在程序的数据段(.data segment)中,但是程序中其他部分能否引用这样的标识符就得看自己的本事了。这个本事跟linkage有关了,你现在要是还没有弄清楚linkage的话,现在回头再看看。这个就是标识符的可见性。
哈哈到这里你结合我前面讲的那个现象可以先静下心来想一想。

实际上在全局生存空间定义的变量和函数如果被加上了static存储标识符的话,他们仅仅在定义他们的源文件中是"可见"的。而其他的在全局生存空间中定义的变量和函数才是真正全局
“可见”的。

 

 

C++中,函数修饰符Function Modifiers)用于改变函数的行为、访问权限、存储特性以及编译器处理方式等。这些修饰符可以分为**函数名前的修饰符**和**函数名后的修饰符**两大类。 ### 函数名前的修饰符 1. **返回值类型** - 返回值类型是定义函数时必须指定的部分,它决定了函数执行后返回的数据类型。 - 可以是基本数据类型如 `void`、`(unsigned) int`、`bool`,也可以是用户自定义类型。 - 还包括 `const` 限定返回值(如 `const int*`),以及 C++11 中新增的 `auto` 关键字用于自动类型推导[^3]。 2. **virtual** - 表示该函数为虚函数,允许子类覆盖其行为,实现多态性。 - 虚函数只能出现在类的成员函数中。 - 示例: ```cpp class Base { public: virtual void show() { cout << "Base"; } }; ``` 3. **inline** - 提示编译器将该函数内联展开,减少函数调用开销。 - 适用于频繁调用且函数体较小的情况。 - 示例: ```cpp inline int add(int a, int b) { return a + b; } ``` 4. **static** - 当修饰类的成员函数时,表示该函数属于类而非类的对象,不能访问非静态成员变量。 - 当修饰普通函数时,限制其作用域仅限于当前文件。 - 示例: ```cpp class MyClass { public: static int count; // 静态成员变量 static void increment() { ++count; } // 静态成员函数 }; ``` 5. **extern** - 声明一个在其他文件中定义的函数。 - 示例: ```cpp extern void externalFunction(); // 在别处定义 ``` 6. **explicit** - 仅用于构造函数,防止隐式类型转换。 - 示例: ```cpp class MyClass { public: explicit MyClass(int value) : val(value) {} private: int val; }; ``` 7. **friend** - 声明一个友元函数,允许其访问类的私有和受保护成员。 - 示例: ```cpp class MyClass { friend void print(const MyClass& obj); private: int data; }; void print(const MyClass& obj) { cout << obj.data; // 可访问私有成员 } ``` 8. **constexpr** - 表示该函数是一个常量表达式函数,可以在编译期求值。 - 示例: ```cpp constexpr int square(int x) { return x * x; } ``` 9. **template** - 声明该函数为模板函数,支持泛型编程。 - 示例: ```cpp template<typename T> T max(T a, T b) { return (a > b) ? a : b; } ``` ### 函数名后的修饰符 1. **const** - 表示该成员函数不会修改类的成员变量。 - 只能被 `const` 对象调用。 - 示例: ```cpp class MyClass { public: int getValue() const { return value; } // 不修改成员变量 private: int value; }; ``` 2. **noexcept** - 指定该函数不会抛出异常。 - 可提高性能并增强代码安全性。 - 示例: ```cpp void safeFunction() noexcept { // 不会抛出异常的代码 } ``` 3. **override** - 明确表明该函数是对基类虚函数的重写。 - 若与基类声明不一致,编译器会报错。 - 示例: ```cpp class Derived : public Base { public: void show() override { cout << "Derived"; } }; ``` 4. **final** - 表示该虚函数不能再被派生类重写。 - 示例: ```cpp class Base { public: virtual void func() final; // 子类不可重写 }; ``` ### 使用建议 - 根据实际需求选择合适的修饰符,例如使用 `const` 来确保接口不会修改对象状态。 - 对于需要在编译期计算的函数,使用 `constexpr` 可提升效率。 - 多态设计中应合理使用 `virtual` 和 `override`。 - `noexcept` 应用于确定不会抛出异常的函数,有助于优化和异常安全设计。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值