
在 C++ 程序设计中,数据的共享与保护是确保程序正确性、安全性和高效性的核心环节。本章将深入探讨标识符的作用域、对象的生存期、类的静态成员、友元机制、共享数据的保护策略、多文件结构及编译预处理等关键知识点。通过理论讲解与实战代码相结合的方式,帮助读者掌握数据共享与保护的精髓。

在 C++ 中,标识符(变量、函数、类等)的作用域指的是标识符有效存在的区域,而可见性则指标识符在程序的哪些部分可以被访问。
C++ 中常见的作用域类型包括:
#include <iostream>
using namespace std;
// 文件作用域:全局变量,在整个文件中有效
int global_var = 100;
void test_function(int param) { // param是函数作用域
// 块作用域1
int local_var = 200;
cout << "函数内局部变量: " << local_var << endl;
// 块作用域2(嵌套块)
{
int nested_var = 300;
// 可以访问外部块和全局变量
cout << "嵌套块变量: " << nested_var << endl;
cout << "访问外部块变量: " << local_var << endl;
cout << "访问全局变量: " << global_var << endl;
}
// 错误:无法访问嵌套块内的变量
// cout << nested_var << endl;
}
int main() {
test_function(5); // 5是函数作用域的参数
cout << "全局变量: " << global_var << endl;
// 错误:无法访问test_function内的局部变量
// cout << local_var << endl;
return 0;
}
可见性遵循 "内层可见外层,外层不可见内层" 的规则,当内层与外层有同名标识符时,内层标识符会隐藏外层标识符。
#include <iostream>
using namespace std;
int var = 10; // 全局变量
void func() {
int var = 20; // 局部变量,隐藏全局变量
cout << "函数内的var: " << var << endl; // 输出20
// 使用::访问被隐藏的全局变量
cout << "全局的var: " << ::var << endl; // 输出10
{
int var = 30; // 嵌套块变量,隐藏外层的局部变量
cout << "嵌套块的var: " << var << endl; // 输出30
cout << "外层局部var: " << ::var << endl; // 这里::仍表示全局
}
}
int main() {
func();
cout << "main中的var: " << var << endl; // 输出10
return 0;
}
对象的生存期指的是对象从创建到销毁的这段时间,根据生存期不同可分为静态生存期和动态生存期。
具有静态生存期的对象在程序运行期间始终存在,包括:
static修饰的局部对象#include <iostream>
using namespace std;
// 全局对象:静态生存期
int global_obj = 10;
void func() {
// 静态局部对象:只初始化一次,程序结束时销毁
static int static_local = 0;
int dynamic_local = 0; // 动态生存期
static_local++;
dynamic_local++;
cout << "静态局部变量: " << static_local << endl;
cout << "动态局部变量: " << dynamic_local << endl;
}
int main() {
cout << "第一次调用func():\n";
func();
cout << "\n第二次调用func():\n";
func();
cout << "\n第三次调用func():\n";
func();
return 0;
}运行结果:

动态生存期的对象在程序执行到创建点时被创建,离开作用域时被销毁,主要是局部非静态对象。

特征 | 动态生存期 | 静态生存期 |
|---|---|---|
存储位置 | 堆内存 | 静态存储区 |
创建方式 | new操作符显式创建 | 自动初始化(全局/静态声明) |
销毁时机 | 手动delete或智能指针离开作用域 | 程序结束时自动销毁 |
生存期控制 | 程序员完全控制 | 编译器管理 |
初始化时机 | 运行时动态创建 | main()前或首次访问时(局部静态) |
内存管理 | 需手动管理,风险:内存泄漏/悬空指针 | 自动管理,风险:初始化顺序问题 |
典型用例 | 运行时决定大小的数据结构 | 全局配置、单例模式、缓存机制 |
动态生存期:
new在堆上分配内存
delete显式销毁
静态生存期:
main()执行前初始化
最佳实践提示:优先使用智能指针(
unique_ptr/shared_ptr)管理动态对象,避免内存泄漏。静态对象需注意初始化顺序问题(跨编译单元时可能未初始化)。
当类的所有对象需要共享同一数据时,可以使用静态成员。静态成员不属于某个特定对象,而是属于整个类。
静态数据成员的特点:
#include <iostream>
#include <string> // 注意添加string头文件
using namespace std;
class Student {
private:
string name;
int id;
// 静态数据成员:统计学生总数
static int count;
public:
// 默认构造函数
Student() : name(""), id(0) {
// 注意:默认构造函数创建的对象是否计入总数,根据需求决定
// 如果不想计入,可以注释掉下面这行
count++;
}
// 带参数的构造函数
Student(string n, int i) : name(n), id(i) {
count++; // 每创建一个对象,总数加1
}
// 析构函数
~Student() {
count--; // 每销毁一个对象,总数减1
}
// 获取学生总数
int getCount() {
return count;
}
void display() {
cout << "姓名: " << name << ", 学号: " << id << endl;
}
};
// 静态数据成员初始化(类外)
int Student::count = 0;
int main() {
// 现在可以创建无参数的Student对象了
cout << "初始学生总数: " << Student().getCount() << endl;
Student s1("张三", 1001);
cout << "创建s1后总数: " << s1.getCount() << endl;
s1.display();
Student s2("李四", 1002);
cout << "创建s2后总数: " << s2.getCount() << endl;
s2.display();
{
Student s3("王五", 1003);
cout << "创建s3后总数: " << s3.getCount() << endl;
s3.display();
} // s3在这里销毁
cout << "销毁s3后总数: " << s2.getCount() << endl;
return 0;
}运行结果:

静态函数成员的特点:
#include <iostream>
using namespace std;
class MathUtil {
private:
// 静态常量:圆周率
static const double PI;
public:
// 静态函数成员:计算圆的面积
static double calculateCircleArea(double radius) {
// 静态函数可以访问静态数据成员
return PI * radius * radius;
}
// 静态函数成员:计算圆的周长
static double calculateCircleCircumference(double radius) {
return 2 * PI * radius;
}
};
// 初始化静态常量
const double MathUtil::PI = 3.1415926535;
int main() {
double radius = 5.0;
// 通过类名直接调用静态函数,无需创建对象
double area = MathUtil::calculateCircleArea(radius);
double circumference = MathUtil::calculateCircleCircumference(radius);
cout << "半径为" << radius << "的圆:" << endl;
cout << "面积: " << area << endl;
cout << "周长: " << circumference << endl;
return 0;
}
友元机制允许类外的函数或其他类访问该类的私有成员,提供了数据共享的灵活性,但会在一定程度上破坏封装性。
友元函数不是类的成员函数,但可以访问类的私有成员。
#include <iostream>
#include <cmath>
using namespace std;
class Point {
private:
double x; // x坐标
double y; // y坐标
public:
// 构造函数
Point(double x = 0, double y = 0) : x(x), y(y) {}
// 声明友元函数:计算两点距离
friend double distanceBetweenPoints(const Point& p1, const Point& p2);
void display() const {
cout << "(" << x << ", " << y << ")" << endl;
}
};
// 实现友元函数
double distanceBetweenPoints(const Point& p1, const Point& p2) {
// 友元函数可以直接访问私有成员x和y
double dx = p1.x - p2.x;
double dy = p1.y - p2.y;
return sqrt(dx*dx + dy*dy);
}
int main() {
Point p1(1, 2);
Point p2(4, 6);
cout << "点p1: ";
p1.display();
cout << "点p2: ";
p2.display();
// 调用友元函数
double dist = distanceBetweenPoints(p1, p2);
cout << "两点之间的距离: " << dist << endl;
return 0;
}
当一个类被声明为另一个类的友元时,这个类的所有成员函数都可以访问另一个类的私有成员。
#include <iostream>
using namespace std;
// 前向声明
class Date;
class Person {
private:
string name;
int age;
public:
Person(string n, int a) : name(n), age(a) {}
// 声明Date类为友元类
friend class Date;
};
class Date {
private:
int year;
int month;
int day;
public:
Date(int y, int m, int d) : year(y), month(m), day(d) {}
// 友元类的成员函数可以访问Person的私有成员
void displayPersonInfo(Person& p) {
cout << "姓名: " << p.name << ", 年龄: " << p.age << endl;
cout << "当前日期: " << year << "-" << month << "-" << day << endl;
}
};
int main() {
Person p("张三", 25);
Date d(2023, 10, 1);
// Date类可以访问Person的私有成员
d.displayPersonInfo(p);
return 0;
}
在多对象共享数据时,需要采取保护措施防止数据被意外修改,const关键字是实现这一目标的重要工具。
常对象的所有成员的值在对象生命周期内不能被修改,只能调用常成员函数。
#include <iostream>
using namespace std;
class Rectangle {
private:
double length;
double width;
public:
// 构造函数
Rectangle(double l, double w) : length(l), width(w) {}
// 常成员函数:不修改成员变量
double getArea() const {
return length * width;
}
// 非常成员函数:修改成员变量
void setDimensions(double l, double w) {
length = l;
width = w;
}
};
int main() {
// 非常对象:可以调用所有成员函数
Rectangle rect1(5, 3);
cout << "rect1面积: " << rect1.getArea() << endl;
rect1.setDimensions(6, 4); // 合法
cout << "修改后rect1面积: " << rect1.getArea() << endl;
// 常对象:只能调用常成员函数
const Rectangle rect2(4, 2);
cout << "rect2面积: " << rect2.getArea() << endl;
// rect2.setDimensions(5, 3); // 错误:常对象不能调用非常成员函数
return 0;
}
const可以修饰类的数据成员和成员函数,分别称为常数据成员和常成员函数。
#include <iostream>
using namespace std;
class Circle {
private:
double radius;
// 常数据成员:初始化后不能修改
const double PI;
public:
// 构造函数初始化列表初始化常数据成员
Circle(double r) : radius(r), PI(3.14159) {}
// 常成员函数:不能修改成员变量
double getArea() const {
// radius = 5; // 错误:常成员函数不能修改普通成员
return PI * radius * radius;
}
// 非常成员函数:可以修改成员变量
void setRadius(double r) {
radius = r;
}
// mutable成员变量:即使在常成员函数中也可以修改
mutable int accessCount;
// 统计访问次数的常成员函数
void countAccess() const {
accessCount++; // 合法:mutable成员可以在常函数中修改
}
};
int main() {
Circle c(5);
cout << "圆面积: " << c.getArea() << endl;
c.setRadius(6);
cout << "修改半径后面积: " << c.getArea() << endl;
// 测试mutable成员
c.accessCount = 0;
c.countAccess();
c.countAccess();
cout << "面积被访问次数: " << c.accessCount << endl;
return 0;
}
常引用(const &)指向的对象不能通过引用被修改,常用于函数参数,避免对象拷贝同时防止数据被修改。
#include <iostream>
#include <string>
using namespace std;
class Book {
private:
string title;
double price;
public:
Book(string t, double p) : title(t), price(p) {}
// 常成员函数
string getTitle() const { return title; }
double getPrice() const { return price; }
// 非常成员函数
void setPrice(double p) { price = p; }
};
// 使用常引用作为参数:避免拷贝,且不能修改原对象
void displayBookInfo(const Book& book) {
cout << "书名: " << book.getTitle() << endl;
cout << "价格: " << book.getPrice() << endl;
// book.setPrice(50); // 错误:不能通过常引用修改对象
}
// 使用普通引用作为参数:可以修改原对象
void discountBook(Book& book, double discount) {
double newPrice = book.getPrice() * (1 - discount);
book.setPrice(newPrice);
}
int main() {
Book book("C++程序设计", 49.9);
// 常引用
const Book& constRef = book;
cout << "通过常引用访问: " << constRef.getTitle() << endl;
// constRef.setPrice(59.9); // 错误:常引用不能修改对象
// 普通引用
Book& ref = book;
ref.setPrice(59.9); // 合法
cout << "修改后价格: " << book.getPrice() << endl;
// 函数中的常引用参数
displayBookInfo(book);
// 函数中的普通引用参数
discountBook(book, 0.1); // 10%折扣
cout << "折扣后价格: " << book.getPrice() << endl;
return 0;
}
大型 C++ 程序通常采用多文件结构,将类的声明、实现和主函数分别放在不同文件中,提高代码的可维护性。
典型的 C++ 程序结构:
1. 头文件(Student.h)
#ifndef STUDENT_H // 防止头文件重复包含
#define STUDENT_H
#include <string>
using namespace std;
class Student {
private:
string name;
int id;
static int count; // 静态数据成员声明
public:
Student(string n, int i); // 构造函数声明
~Student(); // 析构函数声明
void display() const; // 常成员函数声明
static int getCount(); // 静态成员函数声明
};
#endif // STUDENT_H2. 源文件(Student.cpp)
#include "Student.h"
#include <iostream>
// 静态数据成员初始化
int Student::count = 0;
// 构造函数实现
Student::Student(string n, int i) : name(n), id(i) {
count++;
}
// 析构函数实现
Student::~Student() {
count--;
}
// 成员函数实现
void Student::display() const {
cout << "姓名: " << name << ", 学号: " << id << endl;
}
// 静态成员函数实现
int Student::getCount() {
return count;
}3. 主程序文件(main.cpp)
#include "Student.h"
#include <iostream>
int main() {
cout << "初始学生数量: " << Student::getCount() << endl;
Student s1("张三", 1001);
cout << "当前学生数量: " << Student::getCount() << endl;
s1.display();
Student s2("李四", 1002);
cout << "当前学生数量: " << Student::getCount() << endl;
s2.display();
{
Student s3("王五", 1003);
cout << "当前学生数量: " << Student::getCount() << endl;
s3.display();
} // s3在此处销毁
cout << "当前学生数量: " << Student::getCount() << endl;
return 0;
}编译命令(GCC):g++ main.cpp Student.cpp -o student_management
在多文件程序中,外部变量和外部函数可以在多个文件中共享,使用extern关键字声明。
1. 头文件(shared.h)
#ifndef SHARED_H
#define SHARED_H
// 外部变量声明
extern int global_counter;
// 外部函数声明
extern void incrementCounter();
extern void displayCounter();
#endif // SHARED_H2. 源文件(shared.cpp)
#include "shared.h"
#include <iostream>
// 外部变量定义
int global_counter = 0;
// 外部函数定义
void incrementCounter() {
global_counter++;
}
void displayCounter() {
std::cout << "当前计数器值: " << global_counter << std::endl;
}3. 主程序文件(main.cpp)
#include "shared.h"
#include <iostream>
int main() {
displayCounter(); // 输出0
incrementCounter();
incrementCounter();
displayCounter(); // 输出2
global_counter = 5; // 直接访问外部变量
displayCounter(); // 输出5
return 0;
} 编译预处理是在编译前对源代码进行的处理,常用命令包括#include、#define、#ifdef等。
#include <iostream>
using namespace std;
// 宏定义
#define PI 3.14159
#define MAX(a, b) (a > b ? a : b)
#define DEBUG 1 // 调试模式开关
int main() {
double radius = 5.0;
double area = PI * radius * radius; // 使用宏常量
cout << "圆面积: " << area << endl;
int x = 10, y = 20;
cout << "较大的数: " << MAX(x, y) << endl; // 使用宏函数
// 条件编译:仅在DEBUG为真时执行
#ifdef DEBUG
cout << "调试信息: x = " << x << ", y = " << y << endl;
cout << "调试信息: 程序运行中..." << endl;
#endif
#ifndef NDEBUG
cout << "非调试模式未定义,继续执行调试代码" << endl;
#endif
return 0;
}
下面是一个综合运用本章知识点的个人银行账户管理程序,包含静态成员、常成员函数、友元、const 修饰符和多文件结构等特性。
1. 头文件(BankAccount.h)
#ifndef BANKACCOUNT_H
#define BANKACCOUNT_H
#include <string>
using namespace std;
// 前向声明
class BankManager;
class BankAccount {
private:
string accountNumber; // 账号
string accountHolder; // 账户持有人
double balance; // 余额
static int totalAccounts; // 总账户数
public:
// 构造函数
BankAccount(string num, string holder, double initialBalance);
// 析构函数
~BankAccount();
// 存款
void deposit(double amount);
// 取款
bool withdraw(double amount);
// 常成员函数:查询余额
double getBalance() const;
// 常成员函数:显示账户信息
void displayInfo() const;
// 获取总账户数(静态成员函数)
static int getTotalAccounts();
// 声明友元类
friend class BankManager;
};
class BankManager {
public:
// 友元类可以访问BankAccount的私有成员
void transfer(BankAccount& from, BankAccount& to, double amount);
void displayAccountDetails(const BankAccount& account);
};
#endif // BANKACCOUNT_H2. 源文件(BankAccount.cpp)
#include "BankAccount.h"
#include <iostream>
// 初始化静态数据成员
int BankAccount::totalAccounts = 0;
// 构造函数实现
BankAccount::BankAccount(string num, string holder, double initialBalance)
: accountNumber(num), accountHolder(holder), balance(initialBalance) {
if (initialBalance < 0) {
cout << "错误:初始余额不能为负数,已设置为0" << endl;
balance = 0;
}
totalAccounts++;
}
// 析构函数实现
BankAccount::~BankAccount() {
totalAccounts--;
}
// 存款实现
void BankAccount::deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "存款成功!存入金额: " << amount << endl;
} else {
cout << "错误:存款金额必须为正数" << endl;
}
}
// 取款实现
bool BankAccount::withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
cout << "取款成功!取出金额: " << amount << endl;
return true;
} else if (amount <= 0) {
cout << "错误:取款金额必须为正数" << endl;
return false;
} else {
cout << "错误:余额不足" << endl;
return false;
}
}
// 获取余额实现
double BankAccount::getBalance() const {
return balance;
}
// 显示账户信息实现
void BankAccount::displayInfo() const {
cout << "账号: " << accountNumber << endl;
cout << "持有人: " << accountHolder << endl;
cout << "余额: " << balance << " 元" << endl;
}
// 获取总账户数实现
int BankAccount::getTotalAccounts() {
return totalAccounts;
}
// 转账实现
void BankManager::transfer(BankAccount& from, BankAccount& to, double amount) {
cout << "\n尝试转账 " << amount << " 元从账号 "
<< from.accountNumber << " 到账号 " << to.accountNumber << endl;
if (amount <= 0) {
cout << "转账失败:金额必须为正数" << endl;
return;
}
if (from.balance >= amount) {
from.balance -= amount;
to.balance += amount;
cout << "转账成功!" << endl;
} else {
cout << "转账失败:余额不足" << endl;
}
}
// 显示账户详细信息实现
void BankManager::displayAccountDetails(const BankAccount& account) {
cout << "\n===== 账户详细信息 =====" << endl;
cout << "账号: " << account.accountNumber << endl;
cout << "持有人: " << account.accountHolder << endl;
cout << "当前余额: " << account.balance << " 元" << endl;
cout << "======================" << endl;
}3. 主程序文件(main.cpp)
#include "BankAccount.h"
#include <iostream>
int main() {
cout << "===== 个人银行账户管理系统 =====" << endl;
// 显示初始账户数
cout << "\n初始账户总数: " << BankAccount::getTotalAccounts() << endl;
// 创建账户
BankAccount acc1("ACC001", "张三", 1000.0);
BankAccount acc2("ACC002", "李四", 500.0);
// 显示账户总数
cout << "\n当前账户总数: " << BankAccount::getTotalAccounts() << endl;
// 显示账户信息
cout << "\n===== 账户信息 =====" << endl;
acc1.displayInfo();
cout << endl;
acc2.displayInfo();
// 存款和取款操作
cout << "\n===== 账户操作 =====" << endl;
acc1.deposit(500);
cout << "acc1 当前余额: " << acc1.getBalance() << endl;
acc1.withdraw(300);
cout << "acc1 当前余额: " << acc1.getBalance() << endl;
acc2.withdraw(1000); // 余额不足的情况
// 使用友元类进行转账操作
BankManager manager;
manager.transfer(acc1, acc2, 400);
// 使用常引用作为参数的函数调用
const BankAccount& constAccRef = acc1;
cout << "\nacc1 当前余额: " << constAccRef.getBalance() << endl;
// constAccRef.deposit(100); // 错误:常引用不能调用非常成员函数
// 显示账户详细信息
manager.displayAccountDetails(acc1);
manager.displayAccountDetails(acc2);
// 离开作用域前的账户总数
cout << "\n程序结束前账户总数: " << BankAccount::getTotalAccounts() << endl;
return 0;
}编译命令:g++ main.cpp BankAccount.cpp -o bank_management
运行结果:
===== 个人银行账户管理系统 =====
初始账户总数: 0
当前账户总数: 2
===== 账户信息 =====
账号: ACC001
持有人: 张三
余额: 1000 元
账号: ACC002
持有人: 李四
余额: 500 元
===== 账户操作 =====
存款成功!存入金额: 500
acc1 当前余额: 1500
取款成功!取出金额: 300
acc1 当前余额: 1200
取款成功!取出金额: 400
acc1 当前余额: 800
尝试转账 400 元从账号 ACC001 到账号 ACC002
转账成功!
acc1 当前余额: 800
===== 账户详细信息 =====
账号: ACC001
持有人: 张三
当前余额: 800 元
======================
===== 账户详细信息 =====
账号: ACC002
持有人: 李四
当前余额: 900 元
======================
程序结束前账户总数: 2常成员函数的声明需要遵循以下原则:
const关键字放在函数参数列表之后mutable修饰)函数类型 | 常对象能否调用 | 能否修改普通成员 | 能否调用非常成员函数 |
|---|---|---|---|
非常成员函数 | ❌ 不能 | ✅ 能 | ✅ 能 |
常成员函数 | ✅ 能 | ❌ 不能(除非成员为 mutable) | ❌ 不能 |
C++ 程序从源代码到可执行文件需要经过预处理、编译、汇编和链接四个阶段。

1. 预处理阶段 (Preprocessing)
.cpp/.h源文件
#include文件插入(递归处理)
#define宏替换(文本级操作)
#ifdef/#endif)
.i文本文件(无宏/指令)
2. 编译阶段 (Compilation)
.i文件

.s文件)
3. 汇编阶段 (Assembly)
.s文件)
.o或.obj二进制文件)
4. 链接阶段 (Linking)
.a/.lib):直接嵌入可执行文件
.dll/.so):生成引用占位符
.exe/.out)
5. 执行阶段 (Execution)

阶段 | 输入文件 | 输出文件 | 工具示例 |
|---|---|---|---|
预处理 | .cpp/.h | .i | g++ -E, cl /P |
编译 | .i | .s | g++ -S, cl /FA |
汇编 | .s | .o/.obj | as, ml |
链接 | .o/.obj + .a/.lib | .exe/.out | ld, link |
动态链接 | .exe + .so/.dll | 内存映像 | ld-linux.so |
通过
-v编译选项(如g++ -v)可查看详细过程。理解此流程有助于诊断构建错误和优化程序结构。
本章深入探讨了 C++ 中数据共享与保护的核心机制,主要知识点包括:
const关键字用于定义常对象、常成员和常引用,有效防止数据被意外修改。
extern声明外部变量和函数,提高代码的可维护性。
#include、#define和条件编译等预处理命令增强了代码的灵活性和可移植性。
通过本章学习,读者应能熟练运用这些机制设计出数据共享安全、结构清晰的 C++ 程序,为后续面向对象编程打下坚实基础。
数据的共享与保护是 C++ 面向对象编程的重要概念,合理运用本章介绍的技术可以提高程序的安全性、可读性和可维护性。建议读者结合实例代码多做练习,深入理解每个知识点的应用场景和注意事项。如果有任何问题或建议,欢迎在评论区留言讨论!
希望本文对您学习 C++ 有所帮助,如果觉得有用,请点赞、收藏并关注哦!后续会持续更新 C++ 程序设计相关内容。