私有继承、公共继承和受保护继承之间的区别
-
21-08-2019 - |
题
有什么区别 public
, private
, , 和 protected
C++中的继承?我在 SO 上发现的所有问题都涉及具体案例。
解决方案
为了回答这个问题,我想首先用我自己的话来描述成员的访问器。如果您已经知道这一点,请跳至标题“下一步:”。
我知道三个访问器: 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
知道继承。
其他提示
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。这是访问的只是问题。
关于保护和私有继承的使用情况,您可以阅读 href="https://stackoverflow.com/questions/374399/private-protected-inheritance/374423">。
限制继承的可见性将使代码无法看到某个类继承了另一个类:从派生到基数的隐式转换将不起作用,并且 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 样式强制转换有意允许以定义且安全的方式将派生类强制转换为受保护或私有基类,并且也可以强制转换为另一个方向。应不惜一切代价避免这种情况,因为它会使代码依赖于实现细节 - 但如果有必要,您可以使用此技术。
它与如何从派生类公开基类的公共成员有关。
- public -> 基类的公共成员将是公共的(通常是默认值)
- protected -> 基类的公共成员将受到保护
- private -> 基类的公共成员将是私有的
正如 litb 指出的那样,公共继承是您在大多数编程语言中都会看到的传统继承。也就是说,它模拟了“IS-A”关系。私有继承,据我所知是 C++ 所特有的,是一种“根据……实现”的关系。这就是你想要的 使用 派生类中的公共接口,但不希望派生类的用户有权访问该接口。许多人认为,在这种情况下,您应该聚合基类,也就是说,不要将基类作为私有基,而是在派生类的成员中创建以便重用基类的功能。
这三个关键字也用在一个完全不同的上下文,以指定的能见度继承模型即可。
此表收集所有组件声明和继承模型呈现所得到的进入组件的可能的组合的时子类被完全限定。
以上以如下的方式来解释该表(看一看第一行):
如果元件的声明强>作为公开并其类的继承强>作为公开强>所得的访问强>是公开即可。
的示例:
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
类变量p
,q
,r
所得访问的 Subsub 强>是<强>无强>
又如:
class Super {
private: int x;
protected: int y;
public: int z;
};
class Sub : protected Super {};
变量所得到的访问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;
}
在定义的类名为子是类命名Super
或Sub
类的子类被从Super
类派生的。
该Sub
类没有引入新的变量,也没有新的功能。这是否意味着Sub
类的任何对象Super
类其实是一个Super
类对象的副本后,继承了所有的特质?
否即可。它没有。
如果我们编译下面的代码,我们会得到什么,但编译错误说put
和get
方法是无法访问。为什么?
当我们忽略能见度符,编译器假定我们要运用所谓的私有继承。这意味着所有的公共超组件变成的私人连接,私人超组件将不会在所有可访问的。这因此意味着您正在不允许使用子类内后者。
我们必须告知,我们希望保留以前使用的访问策略编译器。
class Sub : public Super { };
的不要被误导的:它并不意味着超级的私有组件 类(如存储变量)会变成在一个公共的人 有些神奇的方式。的私人强>部件将保持的私有强>,公开强> 将保持的公共强>
Sub
类的对象可以做“几乎”同样的事情作为其兄嫂从Super
类创建的。 “几乎” 因为是一个子类的事实也意味着,在类输给超类的私有组件强>访问。我们不能写Sub
类的成员函数,它将能够直接操作存储变量。
这是一个非常严重的限制。有任何解决方法?
是强>
在第三访问级别称为的保护即可。保护关键字是指由任何子类时标有它的组件的的行为就像一个公众一个看起来像一个私人一到世界其他地区即可。 - 这只适用于公开继承类是真正的(如本例中的超级类) -
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;
}
正如你在示例代码中我们看到了新的功能先进而精湛的Sub
类和它一个重要的事情:的它访问从超级类的存储变量即可。
如果变量声明为专用这将是不可能的。 在主要功能范围,所以如果你写的东西一样的变量保持隐藏反正:
object.storage = 0;
编译器将通知你,它是一个error: 'int Super::storage' is protected
。
最后,最后一个节目将产生以下输出:
storage = 101
Member in base class : Private Protected Public
<强>继承型强>:<强>对象继承的强>:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
<强> 1)公共继承强>:
一个。基类的私有成员不是在派生类访问。
湾基类的保护的成员仍然在派生类的保护。
℃。基类的公共成员保持在派生类公共
,因此,其他类可以通过派生类对象使用基类的公共成员。
<强> 2)受保护的继承强>:
一个。基类的私有成员不是在派生类访问。
湾基类的保护的成员仍然在派生类的保护。
℃。基类的公共成员也成为派生类的受保护成员。
,因此,其他的类不能使用通过派生类对象的基类的公共成员;但它们可用于源性子类。
第3)私有继承强>:
一个。基类的私有成员不是在派生类访问。
湾基类的保护及公众成员成为派生类的私有成员。
所以,没有基类的成员可通过其他类可通过派生类对象,因为它们是在派生类私有访问。所以,即便是亚类 类不能访问它们。
公共遗传模型的IS-A的关系。与
class B {};
class D : public B {};
每D
是 B
。
私人遗传模型的IS-IMPLEMENTED-USING关系(或任何这就是所谓的)。与
class B {};
class D : private B {};
一个D
是不的一个B
,但每D
使用其B
其实施。私有继承总是可以通过使用容纳代替被消除:
class B {};
class D {
private:
B b_;
};
此D
,也可以使用其使用B
b_
,在这种情况下实现的。遏制是类型不是继承之间不太紧密耦合,所以一般应是优选的。有时用包容而不是私有继承并不像私有继承一样方便。通常,这是懒惰一个蹩脚的借口。
我不认为任何人知道什么protected
遗传模型。至少我还没有看到任何令人信服的解释呢。
如果你从另一个类继承公开,大家都知道你是继承并且可以多态由任何人通过基类指针来使用。
如果你继承protectedly只有你少儿班就能多态用你。
如果你继承私下只能自己动手就能执行父类的方法。
这基本上标志着说说你的父类的关系。
知识类的其余部分有受保护的数据成员可通过从你的类继承的类被访问。私有数据成员,但是,不能。比方说,我们有以下几点:
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
从您的扩展,该类别中,引用this.myPrivateMember
将无法正常工作。然而,this.myProtectedMember
会。该值仍封装,因此,如果我们把这个类称为myObj
的实例化,然后myObj.myProtectedMember
将无法正常工作,所以它在功能上的私人数据成员类似。
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例子...我觉得有点表胜过千言万语:)概括:
- 私人的:除了班级内其他人都看不到
- 受保护:私有+派生类可以看到
- 民众:世界可以看到它
继承时,您可以(在某些语言中)按某个方向更改数据成员的保护类型,例如从受保护到公开。
私人:
基类的私有成员只能由基类的成员访问。
公开:
基类的公共成员可以通过该基类的成员访问,它的派生类的成员以及其成员是基类和派生类的外部。
受保护的:
基类的保护成员可以通过基类的成员以及其派生的类的成员访问。
简而言之:
<强>私有强>:基
<强>保护强>:碱+衍生
公开强>:基地+ +衍生的任何其他部件
我发现了一个简单的答案,因此想张贴我的未来参考过的。
其从链接 HTTP://www.learncpp的.com / CPP-教程/ 115-继承的和存取指示符/
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
}
它本质上是基类的公共和受保护成员的派生类的访问保护。随着公有继承,派生类可以看到基本的公共和保护成员。随着私有继承,它不能。与受保护的,派生类和任何类从该衍生可以看到它们。