在C++中,"public"、"private "和 "protected "的继承有什么区别?我在SO上找到的所有问题都是针对特定情况的。
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。 这只是访问的问题。
关于protected和private继承的用法,你可以阅读这里。
1:
为了回答这个问题,我想先用我自己的话来描述一下会员的访问器。如果你已经知道这些,请跳到标题"下一个:"。
我所知道的访问器有三个。public
、protected
和private
。
让。
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
Base'的东西也都意识到
Base'包含`publicMember'。Base
包含protectedMember
。Base
,没有人知道privateMember
。我所说的 "知道 "是指 "承认存在,并能够访问"。
同样的情况发生在公有、私有和受保护的继承上。让我们考虑一个 "Base "类和一个继承自 "Base "的 "Child "类。
限制继承的可见性将使代码无法看到某个类继承了另一个类。
从派生类到基类的隐式转换不起作用,从基类到派生类的static_cast
也不起作用。
只有类的成员/朋友可以看到私有继承,只有成员/朋友和派生类可以看到保护继承。
公共继承
class button : public window { }。
保护的继承
boost::compressed_pair
中使用,从空类派生,使用空基类优化,节省内存(下面的例子不使用模板一直在点)。struct empty_pair_impl : 保护 empty_class_1 { non_empty_class_2 second; };
struct pair : 私有的empty_pair_impl { non_empty_class_2 &second() { return this->第二。 }
empty_class_1 &first() { return this; //注意我们返回this! } };
私有继承
template
公共成员
类对 { 公开。 第一名: 第二个第二。 };
2.附件
窗口类 { public.int getWidth()const; int int getWidth() const; };
受保护的成员
类栈 {
保护。
vector
类窗口 { 保护的。 void registerClass(window_descriptor w); };
private成员
窗口类 { 私有的。 int width; };
请注意,C-style casts特意允许以定义的、安全的方式将派生类投向受保护的或私有的基类,也可以投向另一个方向。 应该不惜一切代价避免这样做,因为它会使代码依赖于实现细节--但如果有必要,你可以利用这种技术。
这与基类的公共成员如何从派生类中暴露出来有关。
正如Litb所指出的,公共继承是传统的继承,你会在大多数编程语言中看到。也就是说,它模拟了一种"IS-A"关系。私有继承,AFAIK是C++特有的东西,是一种"实施于"的关系。也就是说,你想在派生类中**使用公共接口,但不希望派生类的用户能够访问该接口。许多人认为,在这种情况下,你应该聚合基类,也就是说,不要把基类作为一个私有的基类,而是把它作为派生类的一个成员,以便重新使用基类的功能。
这三个关键字也在完全不同的上下文中用于指定可见性继承模型。
这个表收集了所有可能的组件声明和继承模型的组合,呈现了子类完全定义后对组件的访问结果。
![在此输入图像描述][1] 。
上表的解释如下(看看第一行)。
*如果一个组件被声明为公共,并且它的类被继承为公共,那么由此产生的访问就是公共。
举个例子。
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
在类Sub中,变量p
、q
、r
的访问结果是none。
另一个例子。
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 { };
不要被误导: 不要被误导。 这并不意味着超级大国的私人组件。
类(如存储变量)将变成公共的,在一个
有点神奇的方式。 私人组件将保持私人,公共。
将保持公开。
Sub
类的对象可以做"几乎"
类的对象可以做和它们从Super
类创建的兄弟姐妹一样的事情。
"几乎"因为作为子类的事实也意味着类失去了对超类私有组件的访问。
我们不能写一个能够直接操作存储变量的子
类的成员函数。
这是一个非常严重的限制。 有没有什么变通的办法?
有的。
第三种访问级别叫做保护。 关键字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
类添加了一个新功能,它做了一件重要的事情。
它从超级类中访问存储变量。
如果变量被声明为私有,这是不可能的。 在主函数的作用域中,这个变量仍然是隐藏的,所以如果你写了这样的内容:{{5713791}。
object.storage = 0;
编译器会通知你这是一个 "错误"。 'int Super::storage' is protected`。
最后,最后一个程序将产生以下输出。
storage = 101
1)公共继承。
a. Base类的私有成员在Derived类中不可访问。
b. Base类的受保护成员在派生类中仍然受保护。
c. Base类的公共成员在派生类中仍然是公共的,所以其他类可以通过派生类对象使用Base类的公共成员。
c. Base类的公共成员在Derived类中仍然是公共的,因此,其他类可以通过Derived类对象使用Base类的公共成员。
2)受保护的继承。
a. Base类的私有成员在Derived类中是不可访问的。
b. Base类的受保护成员在Derived类中仍然受保护。
c. Base类的公共成员也会成为Derived类的保护成员。
所以,其他类不能通过派生类对象使用Base类的公共成员。 但它们可以被衍生类的子类使用。
3) Private Inheritance。
a. Base类的私有成员在Derived类中是不可访问的。
b. 受保护的&.public成员在派生类中成为私有成员。 b. Base类的public成员变成了Derived类的private成员,所以Base类的成员不能通过Derived类被其他类访问。
所以,Base类的成员不能被其他类通过Derived类对象访问,因为它们在Derived类中是私有成员。 所以,即使是Derived类的子类,也不能通过Derived类对象访问Base类的成员。 类不能访问它们。
公共继承模型是一种IS-A关系。 有了
class B {};
class D : public B {};
每一个D
都是一个B
。
Private inheritance model an IS-IMPLEMENTED-USING relationship (or whatever that's called). 有了
class B {};
class D : private B {};
D'不是
B',但每一个D'在其实现中都使用它的
B'。
私有继承总是可以通过使用 containment 来消除。
class B {};
class D {
private:
B b_;
};
这个 "D",也可以用 "B "来实现,在这里用它的 "b_"来实现。 与继承相比,containment在类型之间的耦合性不那么紧密,所以一般情况下应该首选containment。 有时使用containment代替私有继承,不如私有继承方便。 往往这是一个蹩脚的借口,因为懒惰。
我想没有人知道什么是 "保护 "继承模型。 至少我还没有看到任何有说服力的解释。
受保护的数据成员可以被任何继承自你的类的类访问。 但是,私有数据成员却不能。 假设我们有以下内容。
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
在你对这个类的扩展中,引用this.myPrivateMember
是行不通的,但是this.myProtectedMember
可以。
但是,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-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
}