static members1
一个类的static member也称为"class variable", 这是因为它是该类所有对象中共享的,即它的值不会因所属该类对象的不同而发生改变。
它可以用于统计目前该类实例化了多少对象:
// static members in classes
#include <iostream>
using namespace std;
class Dummy {
public:
static int n;
Dummy () { n++; };
};
int Dummy::n=0;
int main () {
Dummy a;
Dummy b[5];
cout << a.n << '\n';
Dummy * c = new Dummy;
cout << Dummy::n << '\n';
delete c;
return 0;
}
6
7
由于static member的独特性,它禁止在类的内部被初始化2,因为类的定义主要用于描述如何创建其对象和行为。但是static member不和任何对象绑定,因此它们的初始化必须分别对待。同时类中的static member仅仅是告知编译器它的存在,但是并没有为其分配存储空间。综上,为了给static member分配存储空间并且进行初始化,我们需要在类的外部进行这个操作,即
int Dummy::n=0;
对于static member functions而言,它们与static member variables类似,它们是该类所有对象公有的。因为对象需要创建才存在,而non- static member是和object绑定的。所以static member functions禁止访问non-static member (neither member variables nor member functions),当然也无法在函数内部使用this关键字。
Const member functions3
当一个类的对象被限定为const时,从类的外部访问其member data时仅能进行read-only,但constructor仍然被自动调用来初始化和修改对象的data。
// constructor on const object
#include <iostream>
using namespace std;
class MyClass {
public:
int x;
MyClass(int val) : x(val) {}
int get() {return x;}
};
int main() {
const MyClass foo(10);
// foo.x = 20; // not valid: x cannot be modified
cout << foo.x << '\n'; // ok: data member x can be read
return 0;
}
10
一个const限定的对象仅能调用其const限定的member functions。而限定member functions为const的方式为在参数列表后()
,函数体前插入const
关键字。例如:
int get() const {return x;}
值得注意的是,因为对象被const限定,因此我们无法修改此对象的state。而non-static members可能有修改其状态的风险,因此禁止const限定的member functions修改non-static data (可以访问)以及调用non-const member functions。
此外,一个类可以根据constness来对其member functions进行重载。在这种情况下,仅有const限定的object可以调用const版本的member function,其他情况的object调用non-const member function。
// overloading members on constness
#include <iostream>
using namespace std;
class MyClass {
int x;
public:
MyClass(int val) : x(val) {}
const int& get() const { cout << "const version" << endl; return x;}
int& get() { cout << "non-const version" << endl; return x;}
};
int main() {
MyClass foo (10);
const MyClass bar (20);
foo.get() = 15; // ok: get() returns int&
// bar.get() = 25; // not valid: get() returns const int&
cout << foo.get() << '\n';
cout << bar.get() << '\n';
return 0;
}
non-const version
non-const version
15
const version
20
更新(2024.4.8):
最近在写类的定义时,对于某个方法是否该使用const限定不是很确定,偶尔会报相关的错误,例如:
/Users/pengchen/CS106/Welcome/chapterExercises.cpp:34: error: 'this' argument to member function 'toString' has type 'const MyHashMap<int, std::string>', but function is not marked const
In file included from ../Welcome/chapterExercises.cpp:3:
../Welcome/myhashmap.h:392:18: error: 'this' argument to member function 'toString' has type 'const MyHashMap<int, std::string>', but function is not marked const
return os << hashmap.toString();
^~~~~~~
../Welcome/chapterExercises.cpp:34:10: note: in instantiation of function template specialization 'operator<<<int, std::string>' requested here
cout << mhp << endl;
^
../Welcome/myhashmap.h:110:17: note: 'toString' declared here
std::string toString();
^
所以继续更新自己对const使用的理解:
- C++中类的方法什么时候需要const限定
在C++中,当你希望某个类的方法不修改类的成员变量时,应该在该方法的声明和定义处使用const限定符。这表明了该方法是一个常量成员函数,它保证不会改变对象的状态。这对于增强代码的安全性和明确方法的意图非常有帮助。具体来说,使用const限定的场景包括但不限于以下几点:
1. 访问器方法(Accessor Methods):通常用于返回对象内部状态但不应该修改对象的方法。例如,获取成员变量的值的方法应该声明为const。
2. 与const对象一起使用:当对象被声明为const时,只能调用其const成员函数。这是因为const对象不应被修改,而const成员函数保证了这一点。
3. 提高方法的通用性:将方法声明为const可以使该方法既能被const对象调用,也能被非const对象调用,从而增加了方法的适用范围。
4. 作为接口的一部分体现类的设计意图:在设计类时,通过合理使用const限定符可以向类的使用者明确哪些方法是安全的“只读”操作,哪些方法可能会修改对象的状态。
由ChatGPT的回答可以看出,如果该成员方法没有修改对象的状态时,就应该使用const限定。第三点原因比较诱人。