提问人: 提问时间:5/14/2009 最后编辑:Jan Schultke 更新时间:9/17/2023 访问量:765206
公共继承、私有继承和受保护的继承有什么区别?
What is the difference between public, private, and protected inheritance?
答:
它与基类的公共成员如何从派生类中公开有关。
- public -> 基类的公共成员将是公共的(通常是默认的)
- protected -> 基类的公共成员将受到保护
- private -> 基类的公共成员将是私有的
正如 litb 所指出的,公共继承是大多数编程语言中都会看到的传统继承。也就是说,它模拟了“IS-A”关系。私有继承是 C++ 特有的 AFAIK,是一种“在方面实现”的关系。也就是说,您希望在派生类中使用公共接口,但不希望派生类的用户有权访问该接口。许多人认为,在这种情况下,您应该聚合基类,也就是说,不要将基类作为私有基,而是在 derived 的成员中加入,以便重用基类的功能。
评论
为了回答这个问题,我想先用我自己的话来描述成员的访问器。如果您已经知道这一点,请跳到标题“下一步:”。
我知道有三个访问器:和 。public
protected
private
让:
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
- 所有知道的东西也知道包含.
Base
Base
publicMember
- 只有孩子(和他们的孩子)知道包含 .
Base
protectedMember
- 没有人知道.
Base
privateMember
我所说的“知道”是指“承认存在,从而能够访问”。
下一个:
公共、私人和受保护的继承也是如此。让我们考虑一个类和一个继承自 的类。Base
Child
Base
- 如果继承是 ,则所有知道并且也知道继承自 的所有东西。
public
Base
Child
Child
Base
- 如果继承是 ,则只有 ,并且其子项知道它们继承自 。
protected
Child
Base
- 如果继承是 ,则除了其他人之外,没有人知道继承。
private
Child
评论
SomeBase
SomeBase
它实质上是对派生类中基类的公共成员和受保护成员的访问保护。通过公共继承,派生类可以查看基的公共成员和受保护成员。对于私人继承,它不能。使用 protected,派生类和从该类派生的任何类都可以看到它们。
受保护的数据成员可由从类继承的任何类访问。但是,私人数据成员不能。假设我们有以下内容:
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
在此类的扩展中,引用将不起作用。但是,会。该值仍然是封装的,因此,如果我们有一个名为 的此类的实例化,则将不起作用,因此它在功能上类似于私有数据成员。this.myPrivateMember
this.myProtectedMember
myObj
myObj.myProtectedMember
总结:
- 私有:除了在班级内,没有人能看到它
- 受保护:私有 + 派生类可以看到它
- 公众:全世界都能看见
继承时,您可以(在某些语言中)按特定方向更改数据成员的保护类型,例如,从受保护更改为公共。
如果你从另一个类公开继承,每个人都知道你正在继承,并且任何人都可以通过基类指针多态地使用你。
如果你以受保护的方式继承,则只有你的子类才能多态地使用你。
如果私下继承,则只有您自己才能执行父类方法。
这基本上象征着其他班级对你与父班级的关系的了解
class A
{
public:
int x;
protected:
int y;
private:
int z;
};
class B : public A
{
// x is public
// y is protected
// z is not accessible from B
};
class C : protected A
{
// x is protected
// y is protected
// z is not accessible from C
};
class D : private A // 'private' is default for classes
{
// x is private
// y is private
// z is not accessible from D
};
重要提示:B、C 和 D 类都包含变量 x、y 和 z。这只是访问问题。
关于受保护继承和私有继承的使用,您可以阅读 此处.
评论
公共继承对 IS-A 关系进行建模。跟
class B {};
class D : public B {};
every 是一个 .D
B
私有继承对 IS-IMPLEMENTED-USING 关系(或任何名称)进行建模。跟
class B {};
class D : private B {};
a 不是 a,但每个 it 都在其实现中使用它。始终可以通过改用包含来消除私有继承:D
B
D
B
class B {};
class D {
private:
B b_;
};
这也可以使用 来实现,在这种情况下,使用其 .与继承相比,包含是类型之间的紧密耦合,因此通常应首选它。有时,使用包含而不是私有继承不如私有继承方便。这通常是懒惰的蹩脚借口。D
B
b_
我认为没有人知道什么是继承模型。至少我还没有看到任何令人信服的解释。protected
评论
D
D
B
B
D
this
D
D
B
using B::member
B
protected
virtual
protected
struct CommonStuff { CommonStuff(Stuff*) {/* assert !=0 */ } }; struct HandlerMixin1 : protected virtual CommonStuff { protected: HandlerMixin1() : CommonStuff(nullptr) {} /*...*/ }; struct Handler : HandlerMixin1, ... { Handler(Stuff& stuff) : CommonStuff(&stuff) {} };
限制继承的可见性将使代码无法看到某个类继承了另一个类:从派生到基的隐式转换将不起作用,从基到派生的隐式转换也不起作用。static_cast
只有类的成员/好友才能看到私有继承,只有成员/好友和派生类才能看到受保护的继承。
公共继承
IS-A 继承。按钮是窗口,任何需要窗口的地方,也可以传递按钮。
class button : public window { };
受保护的继承
受保护的实现方式。很少有用。用于从空类派生并使用空基类优化节省内存(以下示例不使用模板来保持该点):
boost::compressed_pair
struct empty_pair_impl : protected empty_class_1 { non_empty_class_2 second; }; struct pair : private empty_pair_impl { non_empty_class_2 &second() { return this->second; } empty_class_1 &first() { return *this; // notice we return *this! } };
私人继承
就此实施而言。基类的用法仅用于实现派生类。对于特征和大小很重要(仅包含函数的空特征将利用空基类优化)。不过,遏制通常是更好的解决方案。字符串的大小至关重要,因此在这里经常看到这种用法
template<typename StorageModel> struct string : private StorageModel { public: void realloc() { // uses inherited function StorageModel::realloc(); } };
公众成员
骨料
class pair { public: First first; Second second; };
访问
class window { public: int getWidth() const; };
受保护成员
为派生类提供增强的访问
class stack { protected: vector<element> c; }; class window { protected: void registerClass(window_descriptor w); };
私人会员
保留实施详细信息
class window { private: int width; };
请注意,C 样式强制转换特意允许以定义和安全的方式将派生类强制转换为受保护或私有基类,并强制转换为其他方向。应该不惜一切代价避免这种情况,因为它可以使代码依赖于实现细节 - 但如有必要,您可以使用此技术。
评论
私人:
基类的私有成员只能由该基类的成员访问。
公共:
基类的公共成员可以由该基类的成员、其派生类的成员以及基类和派生类之外的成员访问。
保护:
基类的受保护成员可由基类的成员及其派生类的成员访问。
总之:
private:基础
受保护:基础 + 派生
public:基数 + 派生 + 任何其他成员
Member in base class : Private Protected Public
继承类型:对象继承为:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
评论
我找到了一个简单的答案,所以也想把它发布出来供我将来参考。
它来自链接 http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/
class Base
{
public:
int m_nPublic; // can be accessed by anybody
private:
int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
int m_nProtected; // can be accessed by Base member functions, or derived classes.
};
class Derived: public Base
{
public:
Derived()
{
// Derived's access to Base members is not influenced by the type of inheritance used,
// so the following is always true:
m_nPublic = 1; // allowed: can access public base members from derived class
m_nPrivate = 2; // not allowed: can not access private base members from derived class
m_nProtected = 3; // allowed: can access protected base members from derived class
}
};
int main()
{
Base cBase;
cBase.m_nPublic = 1; // allowed: can access public members from outside class
cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}
Accessors | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public | y | y | y
—————————————+————————————+———————————————+———————
protected | y | y | n
—————————————+————————————+———————————————+———————
private | | |
or | y | n | n
no accessor | | |
y: accessible
n: not accessible
基于这个 java 示例...我认为一张小桌子胜过千言万语:)
评论
这三个关键字也用于完全不同的上下文中,以指定可见性继承模型。
此表收集了组件声明和继承模型的所有可能组合,这些模型显示了在完全定义子类时对组件的最终访问。
上表的解释方式如下(请看第一行):
如果将组件声明为 public,并且其类被继承为 public,则生成的访问是 public。
举个例子:
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
在类 Subsub 中,变量 , 的结果访问为 none。p
q
r
另一个例子:
class Super {
private: int x;
protected: int y;
public: int z;
};
class Sub : protected Super {};
在类 Sub 中,变量 的最终访问是受保护的,而变量的访问是 none。y
z
x
一个更详细的例子:
class Super {
private:
int storage;
public:
void put(int val) { storage = val; }
int get(void) { return storage; }
};
int main(void) {
Super object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
现在让我们定义一个子类:
class Sub : Super { };
int main(void) {
Sub object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
名为 Sub 的定义类是 named 或该类的子类,派生自该类。
该类既不引入新变量,也不引入新函数。这是否意味着类的任何对象都继承了该类实际上是类对象的副本之后的所有特征?Super
Sub
Super
Sub
Sub
Super
Super
不可以。事实并非如此。
如果我们编译以下代码,我们只会得到编译错误,说方法不可访问。为什么?put
get
当我们省略可见性说明符时,编译器假定我们将应用所谓的私有继承。这意味着所有公共超类组件都变成了私有访问,私有超类组件将根本无法访问。因此,这意味着您不能在子类中使用后者。
我们必须通知编译器,我们要保留以前使用的访问策略。
class Sub : public Super { };
不要被误导:这并不意味着超级的私人组件 类(如存储变量)将在 有点神奇的方式。私有组件将保持私有,公共组件将保持公共。
类的对象可以“几乎”做与从该类创建的哥哥兄弟姐妹相同的事情。 “几乎”是因为作为子类的事实也意味着该类失去了对超类的私有组件的访问。我们不能编写能够直接操作存储变量的类的成员函数。Sub
Super
Sub
这是一个非常严重的限制。有什么解决方法吗?
是的。
第三个访问级别称为受保护。关键字 protected 意味着标有它的组件在被任何子类使用时的行为类似于公共组件,并且在世界其他地方看起来就像一个私有组件。-- 这仅适用于公开继承的类(如我们示例中的 Super 类) --
class Super {
protected:
int storage;
public:
void put(int val) { storage = val; }
int get(void) { return storage; }
};
class Sub : public Super {
public:
void print(void) {cout << "storage = " << storage;}
};
int main(void) {
Sub object;
object.put(100);
object.put(object.get() + 1);
object.print();
return 0;
}
正如您在示例代码中看到的,我们为该类提供了新功能,它做了一件重要的事情:它从 Super 类访问存储变量。Sub
如果将变量声明为私有变量,则不可能这样做。 在 main 函数作用域中,变量无论如何都是隐藏的,所以如果你写任何内容,比如:
object.storage = 0;
编译器会通知您它是 .error: 'int Super::storage' is protected
最后,最后一个程序将产生以下输出:
storage = 101
评论
if a component is declared as protected and its class is inherited as public the resulting access is protected.
1)公共继承:
一个。在派生类中无法访问 Base 类的私有成员。
b.基类的受保护成员在派生类中仍受保护。
c. 基类的公共成员在派生类中保持公共状态。
因此,其他类可以通过派生类对象使用 Base 类的公共成员。
2) 受保护的继承:
一个。在派生类中无法访问 Base 类的私有成员。
b.基类的受保护成员在派生类中仍受保护。
c. 基类的公共成员也成为派生类的受保护成员。
因此,其他类不能通过 Derived class 对象使用 Base class 的公共成员;但它们可用于 Derived 的子类。
3) 私人继承:
一个。在派生类中无法访问 Base 类的私有成员。
b.基类的受保护和公共成员成为派生类的私有成员。
因此,其他类不能通过派生类对象访问基类的任何成员,因为它们在派生类中是私有的。因此,即使是 Derived 的子类 类无法访问它们。
我试过用下面的图片来解释继承。
要点是父类的私有成员永远无法直接从派生/子类访问,但您可以使用父类的成员函数来访问父类的私有成员。 私有变量始终存在于派生类中,但派生类无法访问它。这就像他们的一样,但你不能亲眼看到,但如果你问家长班的人,那么他可以向你描述。
评论
遗产
- public:无,与基类相同
- protected:公共 -> protected,否则相同。
- private(默认):Public & protected -> private(现在一切都是私有的!)
然后,区分类对象从外部和内部的外观非常重要。
从类内部:您可以从 base 访问所有不是 .继承的种类在这里并不重要。private
从外部:您只能访问公共类中的方法和字段。这意味着基础的接口需要是公共的,并且还需要由 derived 公开继承,以便传输访问权限。
怎么样?protected
受保护基本上意味着:不能从外部获得,而是从内部获得。
下面是一些代码来演示它。所有注释都不会编译:
#include <iostream>
struct base {
private:
int a;
auto get_a() {return a; }
protected:
int b;
auto get_b() {return b; }
public:
int c;
auto get_c() {return c; }
};
struct derive_private : private base {
/* From inside */
auto print() {
// a = 3;
b = 2;
c = 3;
// std::cout << get_a() << std::endl;
std::cout << get_b() << std::endl;
std::cout << get_c() << std::endl;
}
};
struct derive_protected : protected base {
/* From inside */
auto print() {
// a = 3;
b = 14;
c = 35;
// std::cout << get_a() << std::endl;
std::cout << get_b() << std::endl;
std::cout << get_c() << std::endl;
}
};
struct derive_public : public base {
/* From inside */
auto print() {
// a = 3;
b = 14;
c = 35;
// std::cout << get_a() << std::endl;
std::cout << get_b() << std::endl;
std::cout << get_c() << std::endl;
}
};
int main() {
/* From outside */
derive_private mypriv;
mypriv.print();
// mypriv.a = 2;
// mypriv.b = 5;
// mypriv.c = 29;
// std::cout << mypriv.get_a() << std::endl;
// std::cout << mypriv.get_b() << std::endl;
// std::cout << mypriv.get_c() << std::endl;
derive_protected myprot;
myprot.print();
// myprot.a = 17;
// myprot.b = 8;
// myprot.c = 31;
// std::cout << myprot.get_a() << std::endl;
// std::cout << myprot.get_b() << std::endl;
// std::cout << myprot.get_c() << std::endl;
derive_public mypub;
mypub.print();
// mypub.a = 91;
// mypub.b = 101;
mypub.c = 205;
// std::cout << mypub.get_a() << std::endl;
// std::cout << mypub.get_b() << std::endl;
std::cout << mypub.get_c() << std::endl;
}
评论