在 C++ 中,访问私有成员的权限是严格控制的。以下是关于哪些可以访问私有成员、哪些不可以,以及哪些需要通过友元函数来访问的详细说明:
1. 哪些可以访问私有成员?
以下情况可以访问类的私有成员:
(1)类的成员函数
类的所有成员函数(包括构造函数、析构函数、普通成员函数、运算符重载函数)都可以访问该类的私有成员。
class MyClass {
private:
int privateVar;
public:
MyClass(int val) : privateVar(val) {}
void displayPrivate() {
// 成员函数可以访问私有成员
std::cout << "PrivateVar: " << privateVar << std::endl;
}
};
(2)类的友元函数
友元函数是一个被显式声明为 "友元" 的函数,可以直接访问类的私有成员。它既可以是全局函数,也可以是另一个类的成员函数。
class MyClass {
private:
int privateVar;
public:
MyClass(int val) : privateVar(val) {}
// 声明友元函数
friend void displayPrivate(const MyClass& obj);
};
// 全局友元函数
void displayPrivate(const MyClass& obj) {
// 可以直接访问 privateVar
std::cout << "PrivateVar: " << obj.privateVar << std::endl;
}
(3)类的友元类
一个类可以将另一个类声明为友元类,友元类的所有成员函数都可以访问当前类的私有成员。
class MyClass {
private:
int privateVar;
public:
MyClass(int val) : privateVar(val) {}
// 声明友元类
friend class FriendClass;
};
class FriendClass {
public:
void display(const MyClass& obj) {
// 可以访问 MyClass 的私有成员
std::cout << "PrivateVar: " << obj.privateVar << std::endl;
}
};
(4)同类对象之间
同一个类的不同对象可以互相访问私有成员。这是 C++ 的设计特性。
class MyClass {
private:
int privateVar;
public:
MyClass(int val) : privateVar(val) {}
void copyFrom(const MyClass& other) {
// 可以访问 other 对象的私有成员
privateVar = other.privateVar;
}
void display() const {
std::cout << "PrivateVar: " << privateVar << std::endl;
}
};
2. 哪些不能访问私有成员?
以下情况不能直接访问类的私有成员:
(1)普通全局函数
普通的全局函数不能访问类的私有成员,除非它被声明为友元函数。
错误示例:
class MyClass {
private:
int privateVar;
public:
MyClass(int val) : privateVar(val) {}
};
void displayPrivate(const MyClass& obj) {
// 不能访问 privateVar,会编译报错
// std::cout << "PrivateVar: " << obj.privateVar << std::endl;
}
(2)非友元类
非友元类的成员函数不能访问其他类的私有成员。
错误示例:
class MyClass {
private:
int privateVar;
public:
MyClass(int val) : privateVar(val) {}
};
class OtherClass {
public:
void display(const MyClass& obj) {
// 不能访问 privateVar,会编译报错
// std::cout << "PrivateVar: " << obj.privateVar << std::endl;
}
};
(3)继承的子类
子类不能直接访问父类的私有成员,即使子类继承了父类的所有成员。子类只能通过父类的公有或受保护的接口访问父类的私有成员。
错误示例:
class Parent {
private:
int privateVar;
public:
Parent(int val) : privateVar(val) {}
};
class Child : public Parent {
public:
void display() {
// 不能直接访问 privateVar,会编译报错
// std::cout << "PrivateVar: " << privateVar << std::endl;
}
};
3. 哪些需要友元函数?
当某个非类的成员函数需要访问类的私有成员时,就需要将它声明为友元函数。
具体场景:
-
全局函数需要访问私有成员:
- 例如,全局运算符重载函数(如
operator<<
和operator>>
)。
示例:
class MyClass { private: int privateVar; public: MyClass(int val) : privateVar(val) {} // 声明友元函数 friend std::ostream& operator<<(std::ostream& os, const MyClass& obj); }; std::ostream& operator<<(std::ostream& os, const MyClass& obj) { // 友元函数可以访问 privateVar os << "PrivateVar: " << obj.privateVar; return os; }
- 例如,全局运算符重载函数(如
-
非成员函数需要直接访问类的私有成员:
- 如果你不希望将某些逻辑放在类的成员函数内,而是用全局函数实现,又需要访问私有成员时,就可以使用友元。
4. <<
和 >>
是否可以访问私有成员?
运算符 <<
和 >>
是全局函数,默认情况下不能访问类的私有成员。但是如果它们被声明为类的友元函数,则可以访问。
示例:
#include <iostream>
using namespace std;
class MyClass {
private:
int privateVar;
public:
MyClass(int val) : privateVar(val) {}
// 声明友元函数
friend ostream& operator<<(ostream& os, const MyClass& obj);
};
ostream& operator<<(ostream& os, const MyClass& obj) {
// 可以访问 privateVar,因为它是友元
os << obj.privateVar;
return os;
}
int main() {
MyClass obj(42);
cout << obj << endl; // 输出:42
return 0;
}
5. 总结
访问场景 | 是否可以访问私有成员 | 备注 |
---|---|---|
类的成员函数 | 可以 | 成员函数默认可以访问类的私有成员。 |
类的友元函数 | 可以 | 需要显式声明为友元函数。 |
类的友元类 | 可以 | 需要显式声明为友元类,友元类的所有成员函数都可以访问。 |
同类对象 | 可以 | 可以互相访问私有成员。 |
普通全局函数 | 不可以 | 需要声明为友元函数才能访问。 |
非友元类 | 不可以 | 非友元类不能访问其他类的私有成员。 |
子类 | 不可以 | 子类不能直接访问父类的私有成员。 |
运算符 << 和 >> | 不可以 | 除非被声明为友元函数,否则无法访问私有成员。 |