引言
在C++编程中,数据的共享与保护是平衡代码灵活性、安全性和效率的关键。C语言中依赖的全局变量虽能实现数据共享,却破坏了封装性,带来安全隐患。为此,C++提供了静态成员、友元、const修饰、对象指针四大核心机制,既解决了数据共享需求,又通过严格的访问控制保障数据安全。本文将系统解析这些机制的原理、用法及实践场景,结合实例帮助开发者灵活运用。
一、静态成员:类级别的数据共享
静态成员是解决同类对象间数据共享的核心方案,分为静态成员变量和静态成员函数,二者均属于类而非单个对象。
1.1 静态成员变量
核心特性 :用
static关键字定义,所有同类对象共享同一份内存空间,值修改对所有对象生效;不随对象创建/销毁分配/释放空间,编译时即开辟内存。关键用法 :必须在类体外初始化(格式:
数据类型 类名::静态成员变量名=初值),无需加static;可通过类名(类名::变量名)或对象名(对象名.变量名)访问。注意事项:不能通过构造函数参数初始化表初始化。
示例代码:
cpp#include <iostream> #include <string> using namespace std; class Student { public: static int count; // 静态成员变量:统计学生人数 string name; Student(const char* pN = "no name") : name(pN) { count++; // 每创建一个对象,计数+1 } ~Student() { count--; // 每销毁一个对象,计数-1 } }; int Student::count = 0; // 类外初始化 int main() { Student s1("zhangsan"); cout << "当前学生数:" << Student::count << endl; // 输出1 Student s2("lisi"); cout << "当前学生数:" << s2.count << endl; // 输出2 return 0; }
1.2 静态成员函数
核心特性 :用
static修饰,无this指针,主要用于访问本类静态成员变量。关键用法:可通过类名或对象名调用;不能直接访问非静态成员变量,需通过"对象名.非静态成员"间接访问。
示例代码:
cpp#include <iostream> #include <cstring> using namespace std; class Student { protected: static int count; char name[40]; public: Student(const char* pN = "no name") { strcpy_s(name, pN); count++; } static int number() { // 静态成员函数:返回学生数 return count; // 直接访问静态成员变量 } }; int Student::count = 0; int main() { Student s1("zhangsan"), s2("lisi"); cout << Student::number() << endl; // 输出2(通过类名调用) cout << s1.number() << endl; // 输出2(通过对象名调用) return 0; }
二、友元:突破封装的高效访问
类的封装性限制了私有成员的访问,而友元机制通过"开小孔"的方式,允许特定函数或类直接访问私有成员,兼顾效率与灵活性(需慎用,避免过度破坏封装)。
2.1 友元函数(普通函数)
核心特性 :在类体内用
friend声明,类体外按普通函数定义;非成员函数,可直接访问类的所有成员(公有、保护、私有)。声明格式 :
friend 函数返回类型 函数名(参数表列);示例:计算两点间距离:
cpp#include <iostream> #include <math.h> using namespace std; class Point { private: double x, y; public: Point(double i, double j) : x(i), y(j) {} friend double Distance(Point a, Point b); // 友元函数声明 }; // 友元函数定义:直接访问Point的私有成员x、y double Distance(Point a, Point b) { double dx = a.x - b.x; double dy = a.y - b.y; return sqrt(dx*dx + dy*dy); } int main() { Point P1(3.0, 4.0), P2(6.0, 8.0); cout << "Distance is " << Distance(P1, P2) << endl; // 输出5 return 0; }
2.2 友元成员函数
核心特性:一个类的成员函数被声明为另一个类的友元,可访问该类的所有成员。
注意事项:需提前声明被引用的类(前向声明)。
2.3 友元类
核心特性:若类Y是类X的友元,则Y的所有成员函数都是X的友元函数。
关键规则:友元关系不具有传递性(A是B的友元,B是C的友元,A不一定是C的友元)。
示例代码:
cpp#include <iostream> using namespace std; class X { friend class Y; // Y是X的友元类 private: int x; static int y; public: void set(int i) { x = i; } }; int X::y = 10; class Y { private: X a; public: Y(int i, int j) { a.x = i; X::y = j; } // 直接访问X的私有成员 void display() { cout << "x=" << a.x << ", y=" << X::y << endl; } }; int main() { X b; b.set(5); Y c(6, 9); c.display(); // 输出x=6, y=9 return 0; }
三、常对象与常成员:数据不可篡改的保障
const关键字用于声明常量,在类中可修饰成员变量、成员函数和对象,确保数据在共享时不被篡改。
3.1 常成员变量
核心特性 :用
const修饰,必须通过构造函数的成员初始化列表初始化,且终身不可修改。错误示例 :不能在构造函数体内赋值(
A::A(int i){a=i;}编译报错)。正确示例:
cpp#include <iostream> using namespace std; class A { private: const int a; // 常成员变量 public: A(int i) : a(i) {} // 初始化列表初始化 void Print() { cout << a << endl; } }; int main() { A a1(50), a2(30); a1.Print(); // 输出50 a2.Print(); // 输出30 return 0; }
3.2 常对象
声明格式 :
类名 const 对象名或const 类名 对象名。核心特性:对象的所有成员变量终身不可修改;不能调用普通成员函数(仅允许调用常成员函数和隐含的构造/析构函数)。
3.3 常成员函数
声明格式 :
函数返回类型 函数名(参数表列) const;核心特性:可访问常对象的成员变量,但不能修改;普通对象和常对象均可调用。
示例代码:
cpp#include <iostream> using namespace std; class Circle { private: double radius; public: Circle(double r = 0) : radius(r) {} double GetR1() const { return radius; } // 常成员函数 double GetR2() { return radius; } // 普通成员函数 }; int main() { const Circle R1(2.5); // 常对象 Circle R2; // 普通对象 cout << R1.GetR1() << endl; // 合法:常对象调用常成员函数(输出2.5) // cout << R1.GetR2() << endl; // 非法:常对象调用普通成员函数 cout << R2.GetR2() << endl; // 合法:普通对象调用普通成员函数(输出0) return 0; }
3.4 核心应用关系
成员变量/对象类型 非const成员函数 const成员函数 非const成员变量 可引用、可修改 可引用、不可修改 const成员变量 可引用、不可修改 可引用、不可修改 常对象的成员变量 不可引用、不可修改 可引用、不可修改
四、对象指针:灵活访问与安全控制
对象指针用于指向对象或对象成员,结合
const可实现灵活且安全的访问控制,核心包括指向对象的指针、成员指针、this指针等。
4.1 基础对象指针
指向对象的指针 :
类名 *指针名 = &对象名,通过->访问成员(ptr->hour)或(*ptr).成员名。指向对象成员变量的指针 :
数据类型 *指针名 = &对象名.成员变量名。指向对象成员函数的指针 :声明格式
返回类型 (类名::*指针名)(参数表列),赋值格式指针名 = &类名::成员函数名。示例代码:
cpp#include <iostream> using namespace std; class Time { public: int hour, minute, sec; Time(int h, int m, int s) : hour(h), minute(m), sec(s) {} void get_Time() { cout << hour << ":" << minute << ":" << sec << endl; } }; int main() { Time t1(10, 12, 56); Time *p2 = &t1; // 指向对象的指针 p2->get_Time(); // 输出10:12:56 // 指向成员函数的指针 void (Time::*p3)() = &Time::get_Time; (t1.*p3)(); // 输出10:12:56 return 0; }
4.2 this指针
核心作用:隐含在每个非静态成员函数中,指向当前调用函数的对象,用于区分不同对象的成员变量。
本质 :
month = m等价于this->month = m,无需显式声明即可使用。
4.3 带const的对象指针
指针类型 声明格式 核心特性 指向对象的常指针 类名 *const 指针名 = &对象名 指针值(指向)不可改,对象内容可改 指向常对象的指针 const 类名 *指针名 指针值可改,对象内容不可通过指针改 应用场景 :作为函数形参,既避免拷贝开销,又保护数据不被修改(如
void func(const Time *p))。
4.4 对象的常引用
声明格式 :
const 类名 &引用名 = 对象名。核心优势:作为函数形参时,不产生对象拷贝(高效),且禁止修改实参(安全)。
五、实战练习题与答案
选择题:一个类的静态成员变量所表示的属性是( ) 答案:A(是类的或对象的属性)
选择题:类A是类B的友元,类B是类C的友元,则下列说法正确的是( ) 答案:D(以上都不对,友元关系不传递)
编程题:用友元函数求两数的平方差 答案:
cpp#include<iostream> using namespace std; class num { private: float x; public: num(float a) : x(a) {} friend float fun(num a, num b) { return a.x*a.x - b.x*b.x; } }; int main() { float x, y; cin >> x >> y; num n(x), n1(y); cout << fun(n, n1) << endl; return 0; }
- 选择题:下列程序的输出结果为( )
cppint i=0; class A { public: A() {i++;} }; int main() { A a,b[3],*c; c=b; cout<<i<<endl; }答案:C(4,a是1个对象,b[3]是3个对象,共4个,指针c不创建对象)
六、总结
C++的静态成员、友元、const修饰、对象指针四大机制,从不同维度解决了数据共享与保护的核心需求:静态成员实现类级别的数据共享,友元平衡了封装与访问效率,const确保数据不可篡改,对象指针提供了灵活的访问方式。在实际开发中,需根据场景合理选择:如需同类对象共享数据用静态成员,需高效访问私有成员用友元(慎用),需保护数据不被修改用const,需灵活操作对象用指针(结合const提升安全性)。掌握这些机制,能大幅提升代码的安全性、效率与可维护性。