在C++中,类的成员函数是定义在类内部的函数,用于描述类对象的行为或操作。它们可以通过对象或类的实例来调用。成员函数分为几类,包括普通成员函数、构造函数、析构函数、静态成员函数、常量成员函数等。

1. 成员函数的定义方式

  1. 在类内定义:定义直接放在类体内,通常是小型函数
  2. 在类外定义:定义放在类体之外,需要使用作用域解析运算符 :: 来指定函数所属的类

2. 成员函数的访问权限

根据关键字 publicprotectedprivate,成员函数的访问权限分为以下三种:

  • public:可以从类外通过对象访问。
  • protected:只能在类内或派生类中访问。
  • private:仅在类内访问。

3. 普通成员函数

普通成员函数是定义在类内部的函数,用于描述类对象的行为或操作。它们可以通过对象或类的实例来调用。

4. 常成员函数

  • 不允许修改成员变量
  • 在函数声明后加 const 关键字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
private:
int value;
public:
MyClass(int v) : value(v) {}
void display() const { // 常成员函数
std::cout << "Value: " << value << std::endl;
}
};

int main() {
const MyClass obj(10);
obj.display(); // 调用常成员函数
return 0;
}

5. 静态成员函数

  • 使用 static 关键字声明。
  • 不依赖于对象,只能访问静态成员变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
private:
static int count;
public:
static void showCount() { // 静态成员函数
std::cout << "Count: " << count << std::endl;
}
};

int MyClass::count = 5;

int main() {
MyClass::showCount(); // 静态成员函数通过类名调用
return 0;
}

6. 构造函数

构造函数是一种特殊的成员函数,用于初始化对象。它的名字与类名相同,并且没有返回值(连 void 都不能写)。构造函数的主要作用是在创建对象时自动执行初始化操作。
构造函数可以重载,即可以定义多个构造函数,每个构造函数的参数列表不同。当创建对象时,根据传递的参数列表选择合适的构造函数来初始化对象。

6.1. 默认构造函数

不带参数或参数都有默认值的构造函数。

6.2. 带参数的构造函数

带参数的构造函数可以在创建对象时传递参数,用于初始化对象的成员变量。

6.3. 拷贝构造函数

拷贝构造函数是一种特殊的构造函数,用于创建一个新对象,并将另一个对象的值复制到新对象中。它的参数是一个同类对象的引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class MyClass {
public:
int value;
MyClass() { // 默认构造函数
std::cout << "默认构造函数被调用!" << std::endl;
}

MyClass(int v) { // 带参数的构造函数
value = v;
std::cout << "带参数构造函数被调用,value = " << value << std::endl;
}
/*MyClass(int v) : value(v) { // 另一种带参数的构造函数写法
std::cout << "带参数构造函数被调用,value = " << value << std::endl;
}*/

MyClass(const MyClass& obj) { // 拷贝构造函数
value = obj.value;
std::cout << "拷贝构造函数被调用!" << std::endl;
}

};

int main() {
MyClass obj1; // 调用默认构造函数
MyClass obj2(10); // 调用带参数的构造函数
MyClass obj3 = obj2; // 调用拷贝构造函数
return 0;
}

6.4. 委托构造函数(C++11 引入)

委托构造函数是一种特殊的构造函数,它可以在一个构造函数中调用另一个构造函数来初始化对象。这样可以减少代码重复,提高代码的可维护性。

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass {
public:
MyClass() : MyClass(0) {} // 委托到另一个构造函数
MyClass(int x) {
std::cout << "x = " << x << std::endl;
}
};

int main() {
MyClass obj; // 调用默认构造函数,实际委托到 MyClass(int x)
return 0;
}

6.5. 显式构造函数(explicit)

防止隐式类型转换。

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass {
public:
explicit MyClass(int x) {
std::cout << "显式构造函数被调用,x = " << x << std::endl;
}
};

int main() {
MyClass obj1(10); // OK,显式调用
// MyClass obj2 = 20; // 错误,禁止隐式转换
return 0;
}

6.6. 构造函数与初始化列表

使用初始化列表可以更高效地初始化成员变量,尤其是常量或引用成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
int a;
const int b;
int& c;
public:
MyClass(int x, int y, int& z) : a(x), b(y), c(z) { // 初始化列表,这是一个带参数的构造函数
std::cout << "初始化列表构造函数被调用" << std::endl;
}
};

int main() {
int val = 10;
MyClass obj(1, 2, val);
return 0;
}

7. 析构函数

析构函数是一种特殊的成员函数,用于在对象销毁时执行清理操作。它的名字与类名相同,前面加上一个波浪号~,并且没有返回值(连 void 都不能写)。析构函数的主要作用是在对象销毁时自动执行清理操作,例如释放动态分配的内存、关闭文件等。

析构函数只能有一个,不能重载。当对象超出作用域或显式调用 delete 操作符时,会自动调用析构函数。

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass {
public:
~MyClass() { // 析构函数
std::cout << "析构函数被调用,清理资源!" << std::endl;
}
};

int main() {
MyClass obj; // 创建对象时调用构造函数
// 离开作用域时自动调用析构函数
return 0;
}

8. 虚函数

虚函数是一种特殊的成员函数,用于实现多态性。在基类中声明虚函数时,需要在函数声明前加上 virtual 关键字。在派生类中重写虚函数时,不需要使用 virtual 关键字,但必须与基类中的虚函数具有相同的函数签名(即函数名、参数列表和返回类型)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Base {
public:
virtual void show() {
std::cout << "基类 show 函数" << std::endl;
}
};

class Derived : public Base {
public:
void show() override { // 重写虚函数
std::cout << "派生类 show 函数" << std::endl;
}
};

int main() {
Base* ptr = new Derived();
ptr->show(); // 调用派生类的 show 函数
delete ptr;
return 0;
}

9. 纯虚函数

纯虚函数是一种特殊的虚函数,用于定义接口。在基类中声明纯虚函数时,需要在函数声明前加上 virtual 关键字和 = 0。纯虚函数没有函数体,派生类必须重写纯虚函数,否则派生类也将成为抽象类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Base {
public:
virtual void show() = 0; // 纯虚函数
};

class Derived : public Base {
public:
void show() override { // 重写纯虚函数
std::cout << "派生类 show 函数" << std::endl;
}
};

int main() {
Base* ptr = new Derived();
ptr->show(); // 调用派生类的 show 函数
delete ptr;
return 0;
}

10. 内联成员函数

使用 inline 关键字提示编译器将函数展开到调用处。

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass {
public:
inline void greet() { // 内联成员函数
std::cout << "你好!" << std::endl;
}
};

int main() {
MyClass obj;
obj.greet();
return 0;
}

11. 友元函数

友元函数是类的非成员函数,可以在类内部声明,但在类外部定义。友元函数可以访问类的私有成员和保护成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyClass {
private:
int value;
public:
MyClass(int v) : value(v) {}
friend void printValue(const MyClass& obj); // 声明友元函数
};

void printValue(const MyClass& obj) { // 定义友元函数
std::cout << "value = " << obj.value << std::endl;
}

int main() {
MyClass obj(10);
printValue(obj); // 调用友元函数
return 0;
}