1.类内const成员和static成员(2024.04.20)
const | static | static const | |
---|---|---|---|
储存在哪? | 堆区 | 静态区域 | 静态区域 |
初始化应注意 | 列表初始化? | 类外初始化 | 声明时必须初始化 |
所有者 | 对象 | 类 | 类 |
是否可改变 | 不可 | 可改变 | 不可 |
1.1 类内const成员:必须在初始化列表中初始化
- 1.1.1 构造函数各部分说明:初始化列表作用是初始化,构造函数体作用是赋值(和其他逻辑处理)。
所以const成员只能在初始化列表中初始化;如果在初始化列表没有显示初始化,则会执行默认初始化,如果再在函数体中赋值,则违背了const使用目的(初始化后值不能改变)。 - 1.1.2 引申"类型是类成员在不同位置的调用过程":初始化列表作用直接调用拷贝构造函数;构造函数体中则先调用相应传入参数的默认构造、再调用该类的拷贝构造函数或拷贝赋值运算符【相应知识点:C++ Primmer第13章】;
所以数据密集型的类来说,使用初始化列表会提高效率,以下为示例:
#include <iostream>
using namespace std;
class Test1
{
public:
Test1() {cout << "Construct Test1" << endl ;} // 无参构造函数
Test1(const Test1& t1) // 拷贝构造函数
{
cout << "Copy constructor for Test1" << endl ;this->a = t1.a ;
}
Test1& operator = (const Test1& t1) // 重载赋值运算符(也称为重载赋值函数)
{
cout << "assignment for Test1" << endl ;
this->a = t1.a ;
return *this;
}
private:
int a ;
};
class Test2
{
public:
Test1 test1; //此处第二次调用Test 1的construct;
//std::cout<<"进入Test2 的构造函数"<<std::endl; //类中只能包含成员变量和成员函数!
Test2(Test1 &t1){test1 = t1 ;} //此处的“=”调用重载的“=”操作符;
};
int main(){
Test1 t1; //此处第一次调用Test1的construct;
cout<<"end of fist construct t1"<<endl;
Test2 t2(t1);
}
输出
Construct Test1
end of fist construct t1
Construct Test1
assignment for Test1
解释:main函数中,Test2 t2(t1)会首先调用Test2的拷贝构造函数Test2(Test1 &t1){test1 = t1},由于该构造函数没有初始化列表,所以对于t2中的成员test1,会通过调用Test1的无参构造函数生成成员对象test1,然后再通过重载赋值运算符对参数t1进行拷贝test1 = t1。
初始化列表一般是直接初始化,另外其他初始化方式还有默认初始化、拷贝初始化,参考链接
- 1.1.3 误区解释:为什么以下代码不对
class A{const int a = 1;};
解释:定义class的时候不能够对其中的成员变量赋值,因为定义一个class并不会为这个class分配空间,是只有在instance class时候才会分配空间,既然没有空间,当然不能赋值。
改成下面就对了
class A {
public:
const int a;
A() : a(1) {} // 在构造函数初始化列表中初始化const成员变量a
};
其他说明:
- 如果想要一个const成员变量并且在类定义时就给它一个固定的值,同时确保这个值在类的所有实例中都是相同的,那么可以考虑使用static const成员变量,但即使在这种情况下,您也需要在类定义外部进行定义(而不是初始化)。
- const声明变量需要在初始化列表中初始化。(还未对其他初始化方式测试,待学习)
参考引用来源(学习记录使用,如有侵权,请联系删除)
1.2类内Static成员:必须在类外部定义(初始化)
解释:类内的static成员是类级别的变量,而不是对象级别的。这意味着无论创建了多少个类的实例,都只有一个static成员变量存在,故在类外初始化,示例如下。
// MyClass.h
class MyClass {
public:
static int myStaticMember; // 声明static成员
// ...
};
// MyClass.cpp
#include "MyClass.h"
int MyClass::myStaticMember = 0; // 定义并初始化static成员
1.3static const
- static const整型成员(以及枚举类型)有一个特例,它们可以在类定义内部进行初始化;对于非整型static const成员,仍然需要在类外部定义和初始化。
class MyClass {
public:
static const int myStaticConstMember = 42; // 声明并初始化static const整型成员
// ...
};
2.const(2022.06.04)
关于const,参考C++Primmer 2.4.1节
代码如下
#include <iostream>
using namespace std;
int main()
{
int i1 = 5;
int& r1 = i1;
i1 = 10;
cout << "i1 " << i1 << " r1 " << r1 << endl;
r1 = 20;
cout << "i1 " << i1 << " r1 " << r1 << endl;
const int i2 = 50;
const int& r2 = i2;
cout << "i2 " << i2 << " r2 " << r2 << endl;
int i3 = 3;
const int& r3 = i3;
i3 = 30;
//r3 = 40; 这里会报错"左值必须为可修改的表达式",所以常量不可修改
cout << "i3 " << i3 << " r3 " << r3 << endl;
const int i4 = 4; // 这里如果没有对i4进行初始值设定会报错:常量 变量 i4需要初始设定值
//int& r4 = i4; // 会报错,所以无法将非const引用绑定到const对象
cin.get();
return 0;
}
输出
变量地址
有个疑问哈:r3本身不可改变,但是r3可以通过i3间接改变值,有什么应用场景吗?
3.const修饰函数参数
#例如
void function(const string& s){...}
这种通过引用传递(相对于值传递),也就是形参s与实参是同一个参数(地址相同),const表明不会改变参数的值。
我有个疑问哈,请各位大佬解惑一下:如果不加&,仅仅是const string修饰,有什么用途吗?应用场景是什么?
#例如
void function(const string s){...}