C ++中public
,private
和protected
继承有什么区别?我在SO上发现的所有问题都涉及具体案例。
答案 0 :(得分:1340)
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。这只是访问问题。
关于受保护和私有继承的使用,您可以阅读here。
答案 1 :(得分:979)
要回答这个问题,我想先用自己的话来描述会员的访问者。如果您已经知道这一点,请跳至标题“next:”。
我知道有三种访问者: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
以外的任何人都不知道继承。答案 2 :(得分:105)
限制继承的可见性将使代码无法看到某些类继承另一个类:从派生到基础的隐式转换将不起作用,并且从基础到派生的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!
}
};
私有继承
实现合条件方面的。基类的用法仅用于实现派生类。对traits有用,如果size很重要(只包含函数的空特征将使用空基类优化)。但是,通常包含是更好的解决方案。字符串的大小是至关重要的,因此这是一个常见的用法
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风格的强制转换有意允许以定义且安全的方式将派生类强制转换为受保护的或私有的基类,并将其转换为另一个方向。应该不惜一切代价避免这种情况,因为它可以使代码依赖于实现细节 - 但如果有必要,您可以使用这种技术。
答案 3 :(得分:62)
它与如何从派生类公开基类的公共成员有关。
正如litb指出的那样,公共继承是传统的继承,你会在大多数编程语言中看到。那就是模仿“IS-A”关系。私有继承,是C ++特有的AFAIK,是一种“实现的术语”关系。也就是说,您希望在派生类中使用公共接口,但不希望派生类的用户有权访问该接口。许多人认为,在这种情况下,您应该聚合基类,而不是将基类作为私有基础,在派生成员中生成以重用基类的功能。
答案 4 :(得分:57)
这三个关键字也用于完全不同的上下文中,以指定可见性继承模型。
该表收集组件声明和继承模型的所有可能组合,在完全定义子类时显示对组件的结果访问。
上面的表格按以下方式解释(看一下第一行):
如果某个组件声明为公开且其类继承为公开,则为访问 公开。
一个例子:
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
对于子类中变量p
,q
,r
的结果访问权限为无。
另一个例子:
class Super {
private: int x;
protected: int y;
public: int z;
};
class Sub : protected Super {};
对类 Sub 中的变量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的已定义类,它是名为Super
的类的子类,或者Sub
类是从Super
类派生的。
Sub
类既不引入新变量也不引入新函数。这是否意味着Sub
类的任何对象在Super
类实际上是Super
类'对象的副本之后继承了所有特征?
否即可。它没有。
如果我们编译以下代码,我们只会得到编译错误,说明put
和get
方法无法访问。为什么?
当我们省略可见性说明符时,编译器会假定我们将应用所谓的私有继承。这意味着所有公共超类组件变为私有访问权限,私有超类组件根本无法访问。因此,这意味着您不允许在子类中使用后者。
我们必须告知编译器我们要保留以前使用的访问策略。
class Sub : public Super { };
不要被误导:它并不意味着Super的私有组件 class(如存储变量)将变为公共变量 有点神奇的方式。 私有组件将保持私有,公开 将保持公开。
Sub
课程的对象可以做几乎&#34;几乎&#34;与他们从Super
班级创建的兄弟姐妹相同的东西。 &#34;几乎&#34; 因为作为子类的事实也意味着类失去了对超类的私有组件的访问权限。我们不能编写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;
}
正如您在示例代码中看到的那样,我们为Sub
类提供了一项新功能,它执行了一项重要操作:它从Super类访问存储变量。
如果变量被声明为私有,则不可能。 在主函数范围内,变量仍然是隐藏的,所以如果你写了类似的东西:
object.storage = 0;
编译器会通知您它是error: 'int Super::storage' is protected
。
最后,最后一个程序将产生以下输出:
storage = 101
答案 5 :(得分:35)
Member in base class : Private Protected Public
继承类型:对象继承为:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
答案 6 :(得分:24)
1)公共继承:
一个。 Derived类中无法访问Base类的私有成员。
湾Base类的受保护成员在Derived类中保持受保护。
℃。 Base类的公共成员在Derived类中保持公开。
因此,其他类可以通过Derived类对象使用Base类的公共成员。
2)受保护的继承:
一个。 Derived类中无法访问Base类的私有成员。
湾Base类的受保护成员在Derived类中保持受保护。
℃。 Base类的公共成员也成为Derived类的受保护成员。
因此,其他类不能通过Derived类对象使用Base类的公共成员;但它们可用于Derived的子类。
3)私人继承:
一个。 Derived类中无法访问Base类的私有成员。
湾受保护的&amp; Base类的公共成员成为Derived类的私有成员。
因此,其他类不能通过Derived类对象访问Base类的成员,因为它们在Derived类中是私有的。所以,甚至Derived的子类 class无法访问它们。
答案 7 :(得分:19)
公共继承模拟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
继承模型是什么。至少我还没有看到任何令人信服的解释。
答案 8 :(得分:12)
如果你从另一个类公开继承,每个人都知道你是继承的,任何人都可以通过基类指针多态地使用它。
如果您继承受保护,只有您的子类可以多态地使用您。
如果你私下继承,只有你自己才能执行父类方法。
这基本上象征着其他课程与你的父类关系的知识
答案 9 :(得分:9)
从您的类继承的任何类都可以访问受保护的数据成员。但是,私人数据成员不能。假设我们有以下内容:
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
从您的扩展程序到此类,引用this.myPrivateMember
将无效。但是,this.myProtectedMember
会。该值仍然是封装的,因此如果我们有一个名为myObj
的类的实例化,那么myObj.myProtectedMember
将不起作用,因此它在功能上类似于私有数据成员。
答案 10 :(得分:7)
要点:
继承时,您可以(在某些语言中)在某个方向上更改数据成员的保护类型,例如从受保护到公共。
答案 11 :(得分:7)
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的this示例...我认为一张价值千言万语的小桌子:)
答案 12 :(得分:6)
基类的私有成员只能由该基类的成员访问。
基类的公共成员可以由该基类的成员,其派生类的成员以及基类和派生类之外的成员访问。
基类的受保护成员可以由基类成员及其派生类的成员访问。
私人:基地
受保护:base + derived
公开:base + derived +任何其他成员
答案 13 :(得分:4)
我找到了一个简单的答案,所以想过将它发布给我以后的参考资料。
来自链接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
}
答案 14 :(得分:3)
它实质上是派生类中基类的公共成员和受保护成员的访问保护。通过公共继承,派生类可以看到基类的公共成员和受保护成员。有了私有继承,它不能。对于protected,派生类和从中派生的任何类都可以看到它们。
答案 15 :(得分:2)