目录
const成员函数
1. 基本语法
2. const 成员函数的作用
(1) 保证对象不被修改
(2) 提高代码安全性
(3) 支持 const 对象
3. 示例
(1) 基本用法
(2) const 对象只能调用 const 成员函数
(3) mutable 成员变量
4. const 成员函数的重载
初始化列表
基本语法
为什么使用初始化列表
使用示例
注意事项
友元函数
一、友元函数的基本概念
1.1 什么是友元函数?
1.2 友元函数的特点
二、友元函数的声明与定义
2.1 声明友元函数
2.2 定义友元函数
三、友元函数的常见用途
运算符重载
static成员
static成员变量
声明和定义
使用示例
static成员函数
声明和定义
使用示例
注意事项
类型转换
const成员函数
在 C++ 中,const
成员函数 是一种特殊的成员函数,它承诺 不会修改 调用它的对象的状态(即不会修改类的成员变量)。const
成员函数的声明方式是在函数参数列表后加上 const
关键字。
1. 基本语法
class MyClass {
public:void nonConstFunc(); // 普通成员函数(可以修改成员变量)void constFunc() const; // const 成员函数(不能修改成员变量)
};
-
const
成员函数 不能修改类的非mutable
成员变量。 -
非
const
成员函数 可以修改成员变量。
const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改,const休息Date类的Print成员函数,Print隐含的this指针由 Date * const this 变为 const Date * const this
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// void Print(const Date* const this) const
void Print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
2. const
成员函数的作用
(1) 保证对象不被修改
-
如果一个对象被声明为
const
(如const MyClass obj;
),则只能调用它的const
成员函数。 -
如果尝试调用非
const
成员函数,编译器会报错。
(2) 提高代码安全性
-
防止函数意外修改对象状态。
-
使代码更清晰,明确哪些函数会修改对象,哪些不会。
(3) 支持 const
对象
-
如果一个对象是
const
的,只有const
成员函数可以被调用。
3. 示例
(1) 基本用法
#include <iostream>
using namespace std;class Counter {
private:int count;
public:Counter() : count(0) {}// 普通成员函数(可以修改成员变量)void increment() {count++;}// const 成员函数(不能修改成员变量)int getCount() const {// count++; // 错误!不能在 const 函数里修改成员变量return count;}
};int main() {Counter c1;c1.increment(); // 可以调用非 const 函数cout << c1.getCount() << endl; // 可以调用 const 函数const Counter c2;// c2.increment(); // 错误!不能对 const 对象调用非 const 函数cout << c2.getCount() << endl; // 可以调用 const 函数return 0;
}
(2) const
对象只能调用 const
成员函数
const Counter c;
c.increment(); // 错误!不能调用非 const 函数
c.getCount(); // 可以调用 const 函数
(3) mutable
成员变量
如果某个成员变量被声明为 mutable
,即使在 const
成员函数中也可以修改它。
class Logger {
private:mutable int logCount; // 可变的,即使在 const 函数里也能修改
public:void log() const {logCount++; // 允许修改,因为 logCount 是 mutable}
};
4. const
成员函数的重载
可以同时提供 const
和非 const
版本的成员函数,编译器会根据调用对象的 const
性质选择合适的版本。
class Data {
private:int value;
public:int& getValue() { // 非 const 版本(返回可修改的引用)return value;}const int& getValue() const { // const 版本(返回只读的引用)return value;}
};int main() {Data d1;const Data d2;d1.getValue() = 10; // 调用非 const 版本,可以修改// d2.getValue() = 20; // 错误!调用 const 版本,不能修改cout << d2.getValue(); // 可以读取return 0;
}
初始化列表
初始化列表(Initializer List)是 C++ 中用于初始化类成员的一种特殊语法,它在构造函数体执行之前完成成员的初始化。
基本语法
class MyClass {
public:// 初始化列表语法MyClass(int a, double b) : memberA(a), memberB(b) {// 构造函数体}private:int memberA;double memberB;
};
为什么使用初始化列表
-
效率更高:对于类类型成员,使用初始化列表直接调用拷贝构造函数,而在构造函数体内赋值则是先调用默认构造函数再调用赋值运算符。
-
必须使用的情况:
-
初始化 const 成员
-
初始化引用成员
-
初始化没有默认构造函数的类成员
-
使用示例
class Example {
public:// 必须使用初始化列表的情况Example(int &ref, int val) : refMember(ref), constMember(val) {// 构造函数体}// 初始化顺序示例Example(int a, int b) : memberB(a), memberA(b) {// 注意:初始化顺序取决于成员声明顺序,而非初始化列表中的顺序}private:int memberA;int memberB;int &refMember; // 引用成员const int constMember; // const成员
};
注意事项
-
初始化顺序:成员的初始化顺序与它们在类中声明的顺序一致,与初始化列表中的顺序无关。
-
性能考虑:对于内置类型(int, double等),使用初始化列表或在构造函数体内赋值性能差异不大,但对于类类型,初始化列表通常更高效。
-
默认参数:初始化列表可以与默认参数结合使用。
友元函数
一、友元函数的基本概念
友元分为友元类和友元函数
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
1.1 什么是友元函数?
友元函数(friend function)是一个被类声明为"朋友"的非成员函数,它可以访问该类的所有私有和保护成员,就像成员函数一样。友元函数不属于类的成员,但它被授予了访问类私有部分的特权。
class Box {
private:double width;public:Box(double w) : width(w) {}// 声明友元函数friend void printWidth(const Box& box);
};// 友元函数定义
void printWidth(const Box& box) {// 可以访问Box的私有成员widthstd::cout << "Width: " << box.width << std::endl;
}
1.2 友元函数的特点
-
非成员性:友元函数不是类的成员函数
-
特权访问:可以访问类的私有和保护成员
-
单向性:友元关系是单向的,类A声明函数f为友元,不意味着f是类A的成员
-
非传递性:友元关系不传递,A是B的友元,B是C的友元,不意味着A是C的友元
-
非继承性:友元关系不继承,基类的友元不是派生类的友元
二、友元函数的声明与定义
2.1 声明友元函数
友元函数在类内部声明,使用friend
关键字:
class MyClass {
private:int secret;public:MyClass(int s) : secret(s) {}// 声明普通函数为友元friend void showSecret(const MyClass& obj);// 声明其他类的成员函数为友元friend void OtherClass::accessMyClass(const MyClass& obj);
};
2.2 定义友元函数
友元函数的定义与普通函数相同,不需要使用friend
关键字,但是它定义在类外面。
void showSecret(const MyClass& obj) {std::cout << "Secret is: " << obj.secret << std::endl;
}
三、友元函数的常见用途
运算符重载
友元函数常用于重载运算符,特别是当运算符的第一个操作数不是类对象时:
class Complex {
private:double real, imag;public:Complex(double r = 0, double i = 0) : real(r), imag(i) {}// 重载<<运算符为友元函数friend std::ostream& operator<<(std::ostream& os, const Complex& c);// 重载+运算符为友元函数friend Complex operator+(const Complex& c1, const Complex& c2);
};std::ostream& operator<<(std::ostream& os, const Complex& c) {os << c.real << " + " << c.imag << "i";return os;
}Complex operator+(const Complex& c1, const Complex& c2) {return Complex(c1.real + c2.real, c1.imag + c2.imag);
}
static成员
在C++中,static
关键字用于类的成员时,有特殊的含义和作用。static成员分为static成员变量和static成员函数。
static成员变量
static成员变量是属于类本身的,而不是类的某个特定对象。这意味着:
-
类所有对象共享:所有类的对象共享同一个static成员变量
-
独立于对象存在:即使没有创建类的任何对象,static成员变量也存在
-
存储位置:存储在全局数据区,而不是对象的存储空间中
-
静态成员也是类的成员,受public、protected、private访问限定符的限制
声明和定义
class MyClass {
public:static int count; // 声明static成员变量
};int MyClass::count = 0; // 定义并初始化static成员变量(必须在类外)
使用示例
#include <iostream>
using namespace std;class Counter {
public:static int count; // 声明Counter() {count++;}~Counter() {count--;}
};int Counter::count = 0; // 定义并初始化int main() {cout << "Initial count: " << Counter::count << endl;Counter c1;cout << "After c1: " << Counter::count << endl;{Counter c2;cout << "After c2: " << Counter::count << endl;}cout << "After c2 destroyed: " << Counter::count << endl;return 0;
}
static成员函数
static成员函数也是属于类而非特定对象的,具有以下特点:
-
只能访问static成员:不能直接访问类的非static成员变量或成员函数
-
没有this指针:因为没有绑定到特定对象
-
可通过类名直接调用:不需要通过对象实例调用
声明和定义
class MyClass {
public:static void staticFunc(); // 声明
};void MyClass::staticFunc() { // 定义// 实现代码
}
使用示例
#include <iostream>
using namespace std;class MathUtility {
public:static int add(int a, int b) {return a + b;}static int subtract(int a, int b) {return a - b;}
};int main() {cout << "5 + 3 = " << MathUtility::add(5, 3) << endl;cout << "5 - 3 = " << MathUtility::subtract(5, 3) << endl;return 0;
}
注意事项
-
static成员变量必须在类外定义和初始化(C++17引入了inline static可以在类内初始化)
-
static成员函数不能是const或volatile的
-
static成员函数不能被声明为virtual
-
static成员可以被继承,但遵循常规的访问控制规则
-
静态成员变量不能在生命位置给缺省值初始化,因为缺省值是给构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表。
类型转换
C++支持内置类型隐式类型转换为类类型对象,需要有相关内置内省为参数的构造函数
构造函数前面加explicit就不再支持隐式类型转换
类类型的对象之间也可以隐式转换,需要相应的构造函数支持