C++ 成员函数
在 C++ 中,成员函数(Member Function)是定义在类(class)或结构(struct)内部的函数,它属于该类的成员。成员函数可以直接访问类的所有成员,包括私有(private)、保护(protected)和公有(public)的成员变量和函数。成员函数通常用来操作类的对象数据或提供类的行为接口。
简单来说,成员函数是类的一部分,与类的对象绑定在一起,描述了对象能够执行的操作。例如,在一个表示“汽车”的类中,成员函数可能是“启动引擎”或“加速”。
为什么需要成员函数?
基于面向对象的设计思想,对象具有的的行为可以看作是与对象深度绑定的函数组成的,因此成员函数也可以称为成员行为或成员方法,成员函数体现了面向对象封装的特点,是面向对象编程中封装的重要组成部分。通过成员函数,类可以将数据(成员变量)与操作这些数据的行为(成员函数)绑定在一起,避免外部直接访问数据,从而保护数据的完整性。
成员函数定义了对象可以做什么。例如,一个“人”类可能有“走路”或“说话”的成员函数,反映现实世界中对象的实际行为。并且可以访问类的私有成员,而外部函数无法直接做到这一点,这提供了更高的灵活性和安全性。
如何使用成员函数?
成员函数的定义和使用分为以下几个步骤:
声明成员函数:在类中声明函数,通常在类的头文件中。
定义成员函数:在类外或类内提供函数的具体实现。
调用成员函数:通过类的对象或指针使用点号(.)或箭头(->)运算符调用。
声明和定义成员函数的示例如下:
#include <iostream>
using namespace std;
class Car {
public:
int speed; // 成员变量
// 成员函数声明
void accelerate(int increment);
void displaySpeed();
};
// 成员函数定义(类外实现)
void Car::accelerate(int increment) {
speed += increment;
}
void Car::displaySpeed() {
cout << "Current speed: " << speed << " km/h" << endl;
}
int main() {
Car myCar; // 创建对象
myCar.speed = 0; // 初始化成员变量
myCar.accelerate(50); // 调用成员函数
myCar.displaySpeed(); // 调用成员函数
return 0;
}
C++ 中成员函数的定义方式
-
在类内部定义:
直接在类中编写函数实现,适合简单函数。
class Car { public: int speed = 0; void accelerate(int increment) { speed += increment; } };
-
在类外部定义:
在类中声明函数,在类外使用作用域解析运算符(::)定义函数,适合复杂函数。
class Car { public: int speed; void accelerate(int increment); // 声明 }; void Car::accelerate(int increment) { speed += increment; }
-
内联函数:
使用 inline 关键字或在类内定义(隐式内联),可以减少函数调用的开销。
class Car { public: int speed = 0; inline void accelerate(int increment) { speed += increment; } };
-
静态成员函数
使用 static 关键字定义,不依赖于对象实例,只能访问类的静态成员。
class Car { public: static int totalCars; static void addCar() { totalCars++; } }; int Car::totalCars = 0;
成员函数与 this 指针
在每个非静态成员函数中,C++ 隐式传递一个指向调用成员函数的对象的指针,称为 this 指针。
this 是一个常量指针(T* const this),指向当前对象并且表明 this 不可修改指向的对象只能指向调用成员函数的对象,允许成员函数访问对象的成员变量和函数。
当函数参数名与成员变量名冲突时,可以用 this-> 明确指定成员变量。
成员函数可以通过在其声明后添加 const 关键字,成为常量成员函数,表示该函数不会修改对象的成员变量。
const 修饰的成员函数与非 const 版本可以形成重载,编译器根据对象的常量性选择调用哪个版本。
在 const 成员函数中,this 的类型变为 const T* const,限制了对非 mutable 成员变量的修改。
示例如下:
#include <iostream>
using namespace std;
class MyClass {
private:
int value;
public:
MyClass(int v) : value(v) {}
// 非 const 成员函数
void setValue(int value) {
this->value = value; // 使用 this 区分参数和成员变量
}
// const 成员函数
int getValue() const {
return value; // 不会修改对象
}
// 非 const 重载
void display() {
cout << "Non-const version: " << value << endl;
}
// const 重载
void display() const {
cout << "Const version: " << value << endl;
}
};
int main() {
MyClass obj(10);
const MyClass constObj(20);
obj.setValue(15);
cout << "obj value: " << obj.getValue() << endl; // 调用非 const 对象
obj.display(); // 调用非 const 版本
cout << "constObj value: " << constObj.getValue() << endl; // 调用 const 对象
constObj.display(); // 调用 const 版本
return 0;
}
成员函数的名称查找与隐藏关系
在函数作用域内,局部变量或形参会隐藏外部同名的变量或函数。对于成员函数,形参名可能会隐藏类的成员变量,因此可以使用 this 指针显示区分成员变量和形参。
类中定义的名称(成员变量或函数)会隐藏外部作用域(如全局作用域)的同名实体。
如果需要访问外部名称,可以使用作用域解析运算符 ::
示例如下:
#include <iostream>
using namespace std;
int x = 100; // 全局变量
class Test {
private:
int x = 10; // 类成员隐藏全局变量
public:
void setX(int x) { // 形参隐藏成员变量
this->x = x; // 使用 this 访问成员变量
}
void print() {
cout << "Member x: " << x << endl;
cout << "Global x: " << ::x << endl; // 使用 :: 访问全局变量
}
};
template <typename T>
class TemplateTest {
private:
T value;
public:
void setValue(T v) {
this->value = v; // 依赖型名称查找,必须用 this->
}
T getValue() { return value; }
};
int main() {
Test t;
t.setX(20);
t.print();
TemplateTest<int> tt;
tt.setValue(30);
cout << "Template value: " << tt.getValue() << endl;
return 0;
}
静态成员函数
使用 static 关键字定义静态成员函数,静态成员函数不依赖于对象实例,没有隐式的 this 指针,只能访问类的静态成员(变量或函数)。可以通过类名直接调用,也可以通过对象调用。
示例如下:
#include <iostream>
using namespace std;
class Counter {
private:
static int count; // 静态数据成员
public:
Counter() { count++; } // 构造函数增加计数
static int getCount() { // 静态成员函数
return count; // 返回静态数据成员
}
};
int Counter::count = 0; // 静态成员初始化
int main() {
Counter c1, c2, c3;
cout << "Total objects: " << Counter::getCount() << endl; // 通过类名调用
cout << "Total objects: " << c1.getCount() << endl; // 通过对象调用
return 0;
}
成员函数基于引用限定符的重载
C++11 引入了引用限定符(& 和 &&),用于限制成员函数的调用对象是左值(lvalue)还是右值(rvalue)。
& 表示函数只能被左值对象调用,&& 表示只能被右值对象调用。
可以与 const 结合使用,形成更细粒度的重载。
示例如下:
#include <iostream>
using namespace std;
class Example {
private:
int data;
public:
Example(int d) : data(d) {}
// 左值版本
void display() & {
cout << "Lvalue: " << data << endl;
}
// 右值版本
void display() && {
cout << "Rvalue: " << data << endl;
}
// const 左值版本
void display() const & {
cout << "Const Lvalue: " << data << endl;
}
};
int main() {
Example e1(10);
e1.display(); // 调用左值版本
Example(20).display(); // 调用右值版本
const Example e2(30);
e2.display(); // 调用 const 左值版本
return 0;
}