在 C++ 中,子类(派生类)访问父类(基类)的成员受到访问控制和*继承方式的约束。
1. 基类成员的访问说明符
基类中的成员可以声明为:
-
public :任何地方都能访问。
-
protected :类自身、派生类、友元可以访问。
-
private:仅类自身和友元可以访问,派生类**不能**直接访问。
2. 继承方式对成员访问级别的影响
继承方式(public、protected、private)决定了基类成员在派生类中的访问级别:
| 基类成员访问级别 | public 继承 | protected 继承 | private 继承 |
|---|---|---|---|
public |
变成 public |
变成 protected |
变成 private |
protected |
变成 protected |
变成 protected |
变成 private |
private |
不可访问 | 不可访问 | 不可访问 |
-
public继承 :最常用,保持"is-a"关系。基类的public成员在派生类中仍是public,protected仍是protected。 -
protected继承 :基类public和protected成员在派生类中都成为protected。 -
private继承 :基类所有成员(除private外)在派生类中成为private,用于实现"has-a"关系或组合。
3. 派生类访问基类成员的具体规则
无论采用何种继承方式,派生类**永远无法直接访问**基类的 `private` 成员。
派生类只能直接访问基类中 `public` 和 `protected` 的成员(但具体能否访问还受继承方式影响,如上表所示)。
示例:public 继承
cpp
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
class Derived : public Base {
public:
void func() {
pub = 10; // OK:基类的 public 成员
prot = 20; // OK:基类的 protected 成员
// priv = 30; // 错误:不能访问基类的 private 成员
}
};
示例:protected 继承
cpp
class Derived : protected Base {
public:
void func() {
pub = 10; // OK:基类的 public 成员在派生类中变为 protected
prot = 20; // OK:基类的 protected 成员仍为 protected
// priv = 30; // 错误:私有成员不可访问
}
};
int main() {
Derived d;
// d.pub = 10; // 错误:在外部无法访问,因为 pub 在派生类中已是 protected
return 0;
}
4. 如何间接访问基类的私有成员?
派生类无法直接访问基类的私有成员,但可以通过基类提供的公有或受保护成员函数间接访问:
-
公有成员函数 :基类提供
getter/setter函数。 -
受保护成员函数 :若基类希望派生类能够访问但又不想暴露给外部,可将函数声明为
protected。
cpp
class Base {
private:
int secret;
public:
Base(int s) : secret(s) {}
int getSecret() const { return secret; } // 公开接口
protected:
void setSecret(int s) { secret = s; } // 仅派生类可调用的修改接口
};
class Derived : public Base {
public:
Derived(int s) : Base(s) {}
void show() {
std::cout << getSecret() << std::endl; // 通过公有函数访问
setSecret(100); // 通过受保护函数修改
}
};
5. 友元与继承
-
如果基类将派生类声明为**友元**,则派生类可以直接访问基类的私有成员。但这种做法破坏了封装,通常不推荐。
-
友元关系不能继承:基类的友元不会自动成为派生类的友元,反之亦然。
cpp
class Base {
private:
int secret;
friend class Derived; // 派生类成为基类的友元
};
class Derived : public Base {
public:
void access() {
secret = 10; // OK:因为 Derived 是 Base 的友元
}
};
6. 特殊情况:基类成员与派生类成员同名
当派生类定义了与基类同名的成员时,基类成员会被隐藏。如需访问基类成员,需使用作用域运算符 `::`:
cpp
class Base {
public:
int x;
};
class Derived : public Base {
public:
int x; // 隐藏了基类的 x
void func() {
x = 10; // 访问派生类自己的 x
Base::x = 20; // 访问基类的 x
}
};
总结
-
派生类只能直接访问 基类的
public和protected成员(具体能否访问还受继承方式影响)。 -
基类的
private成员永远不能 被派生类直接访问,但可通过基类提供的public/protected成员函数间接操作。 -
选择合适的继承方式(通常为
public)来正确表达设计意图。 -
使用
protected成员来平衡封装性与派生类的访问需求。