在学习中发现对const在限定函数的作用有些模糊,以下为笔者的学习总结
1.5cv限定符及一些关键字在限定函数的作用
-
c(const)v(volatile)
-
const
:用于表示该函数不会改变类的成员变量,所以是可以修改全局变量的 -
volatile
:用于告诉编译器该对象可能会被程序外部修改#include <iostream> #include <string> int year = 2023; // 全局变量 class Peoson { private: std::string name; int age; public; void getYear() const { // age = 1; 错误 year = getYear(); // 全局变量,可以修改 std::cout << year << endl; } }; int main() { Person m; m.getYear(); return 0; }
-
例:
- const 限定符:
const 用于声明一个常量对象,表示该对象的值不能被修改。例如:
const int x = 5; // x 是一个常量整数,值不能改变 // x = 10; // 这行会导致编译错误
- volatile 限定符:
volatile 用于告诉编译器该对象可能会被程序以外的因素(如硬件)改变,因此不要对其进行优化。例如:
volatile int sensor_value; // 这个值可能会被硬件设备随时更改
- 同时使用 const 和 volatile:
const volatile int real_time_clock; // 值不能被程序修改,但可能会被硬件更新
- mutable 说明符:
mutable 允许在 const 对象中修改特定成员。例如:
class Example { mutable int cache_value; public: void update_cache() const { cache_value = 42; // 即使在 const 方法中也可以修改 } };
这些限定符主要用于:
- 防止意外修改(const)
- 处理可能被外部因素更改的数据(volatile)
- 在需要时允许局部修改(mutable)
-
-
&(左值)和&&(右值):表明该函数只能被左值或右值调用
#include <iostream> class MyString { public: void Print() & { std::cout << "左值" << std::endl; } void Print() && { std::cout << "右值" << std::endl; } }; int main() { MyString test; test.Print(); // 左值 MySting().Print();// 右值 return 0; }
-
显式调用成员函数(C++23新特性):
- 左值:代表有明确地址和持久对象(在内存中存在且可以被引用),例如变量
d
和cd
。 - 右值:代表临时对象或字面量,通常是没有持久地址的。例如
std::move(d)
会将d
转换为一个右值引用(Derived&&
)。
class MyClass { public: void normalFunction(int x) { // 隐式调用 value = x; } // 2。 void explicitFunciton(this MyClass& self, int x) { // 显式调用 self.value = x; } // 3. template<typename Self> void anyExplicitFunction(this Self& self, int x) { self.value = x; } private: int value; };
MyClass test; test.normalFunction(1); test.explicitFunciton(1); test.anyExplicitFunction(1); // 这里是左值调用,所以self是&test且为非const // 效果是一样的
- 左值:代表有明确地址和持久对象(在内存中存在且可以被引用),例如变量
-
当我们调用
test.explicitFunciton(1);
的时候,编译器把其转换成了类似于这样的代码MyClass::explicitFunciton(test, 1);
-
第二种优势
清晰性: 显式地看到
this
参数可以使代码意图更清晰。灵活性: 可以更灵活地控制
this
的类型,比如是否为 const, 是左值还是右值引用等。模板推导: 在模板中,可以推导出
this
的确切类型,这在继承情况下特别有用。 -
第三种优势
它能自动处理 const 和非 const 对象。
它能处理左值和右值。
-
例子
class Base { public: template<typename Self> void print(this Self&& self) { //直接写&&,会根据调用的参数来决定是左值还是右值 std::cout << "I am " << self.getName() << std::endl; } virtual std::string getName() const { return "Base"; } }; class Derived : public Base { public: std::string getName() const override { return "Derived"; } }; int main() { Base b; Derived d; const Derived cd; b.print(); // 输出: I am Base d.print(); // 输出: I am Derived cd.print(); // 输出: I am Derived,注意这里调用的是 const 版本 // 使用右值 std::move(d).print(); // 也能正确工作,Self 被推导为 Derived&& // std::move(<对象名>) // 把对象从左值转换为右值 }
-
如果传的对象是const对象,只能调用const类型的成员函数,那么该函数会转换为const类型,反之非const,即为非const类型函数
-
虽然这些特性的业务作用普通的类和对象都支持,但是这有着更简介的写法,让代码易于维护
-
更简洁的写法:通过简化函数模板的定义,使得代码更简洁。
易于维护:清晰的语法和显式的
this
参数声明有助于提高代码的可读性和维护性。减少重载:能够在一个模板中处理不同的
this
类型,减少了重载函数的需求,简化了代码结构。
-
参考链接
[ https://zh.cppreference.com/w/cpp/language/member_functions#const.E3.80.81volatile_.E5.8F.8A.E5.BC.95.E7.94.A8.E9.99.90.E5.AE.9A.E7.9A.84.E6.88.90.E5.91.98.E5.87.BD.E6.95.B0 ]: