952 c++ inheritance encapsulation c++-faq access-specifier
是什么区别public,private以及protected用C++继承?我在SO上发现的所有问题都涉及具体案例.
Kir*_*sky 1392
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
};
Run Code Online (Sandbox Code Playgroud)
重要说明:B,C和D类都包含变量x,y和z.这只是访问问题.
关于受保护和私有继承的使用,您可以在这里阅读.
Anz*_*rio 1023
要回答这个问题,我想先用自己的话来描述成员的访问者.如果您已经知道这一点,请跳至标题"next:".
有三个访问器,我所知道的:public,protected和private.
让:
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
Run Code Online (Sandbox Code Playgroud)
Base也意识到Base包含publicMember.Base包含protectedMember.Base知道privateMember.通过"意识到",我的意思是"承认存在,从而能够访问".
公共,私有和受保护的继承也是如此.让我们考虑一个继承自的类Base和类.ChildBase
public,所有知道Base并且Child也知道Child继承自的东西Base.protected只是Child和它的子进程知道它们是继承的Base.private,除了Child知道继承之外没有人.Joh*_*itb 110
限制继承的可见性将使代码无法看到某些类继承另一个类:从派生到基类的隐式转换将不起作用,并且static_cast从基础到派生的隐式转换也不起作用.
只有类的成员/朋友才能看到私有继承,只有成员/朋友和派生类才能看到受保护的继承.
公共继承
IS-A继承.按钮是一个窗口,在需要窗口的任何地方,也可以传递按钮.
class button : public window { };
Run Code Online (Sandbox Code Playgroud)受保护的继承
受保护的实施条款.很少有用.用于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!
}
};
Run Code Online (Sandbox Code Playgroud)私人继承
实现合条件方面.基类的用法仅用于实现派生类.对traits有用,如果size很重要(只包含函数的空特征将使用空基类优化).但是,通常遏制是更好的解决方案.字符串的大小是至关重要的,因此这是一个常见的用法
template<typename StorageModel>
struct string : private StorageModel {
public:
void realloc() {
// uses inherited function
StorageModel::realloc();
}
};
Run Code Online (Sandbox Code Playgroud)公共成员
骨料
class pair {
public:
First first;
Second second;
};
Run Code Online (Sandbox Code Playgroud)访问器
class window {
public:
int getWidth() const;
};
Run Code Online (Sandbox Code Playgroud)受保护的成员
为派生类提供增强的访问权限
class stack {
protected:
vector<element> c;
};
class window {
protected:
void registerClass(window_descriptor w);
};
Run Code Online (Sandbox Code Playgroud)私人会员
保持实施细节
class window {
private:
int width;
};
Run Code Online (Sandbox Code Playgroud)请注意,C样式转换有意允许以定义和安全的方式将派生类转换为受保护的或私有的基类,并且也可以转换到另一个方向.应该不惜一切代价避免这种情况,因为它可以使代码依赖于实现细节 - 但如果有必要,您可以使用这种技术.
Dou*_* T. 62
它与如何从派生类公开基类的公共成员有关.
正如litb指出的那样,公共继承是传统的继承,你会在大多数编程语言中看到.那就是模仿"IS-A"关系.私有继承,是C++特有的AFAIK,是一种"实现的术语"关系.也就是说,您希望在派生类中使用公共接口,但不希望派生类的用户有权访问该接口.许多人认为,在这种情况下,您应该聚合基类,而不是将基类作为私有基础,在派生成员中生成以重用基类的功能.
Bug*_*tGG 60
这三个关键字也用于完全不同的上下文中,以指定可见性继承模型.
此表收集组件声明和继承模型的所有可能组合,在完全定义子类时显示对组件的结果访问.

上面的表格按以下方式解释(请看第一行):
如果组件声明为public且其类继承为public,则生成的访问权限是公共的.
一个例子:
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
Run Code Online (Sandbox Code Playgroud)
变量产生的访问p,q,r类Subsub是没有.
另一个例子:
class Super {
private: int x;
protected: int y;
public: int z;
};
class Sub : protected Super {};
Run Code Online (Sandbox Code Playgroud)
变量产生的访问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;
}
Run Code Online (Sandbox Code Playgroud)
现在让我们定义一个子类:
class Sub : Super { };
int main(void) {
Sub object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
定义的类名为Sub,它是已命名的类的子类,Super或者Sub该类是从Super类派生的.该Sub课程介绍既不是新的变量,也没有新的功能.是否意味着Sub类的任何对象在类Super实际上是Super类对象的副本之后继承了所有特征?
不.它没有.
如果我们编译以下代码,我们将得到的只是编译错误,说明put并且get方法不可访问.为什么?
当我们省略可见性说明符时,编译器会假定我们将应用所谓的私有继承.这意味着所有公共超类组件都变成私有访问,私有超类组件根本不可访问.因此,它意味着您不允许在子类中使用后者.
我们必须告知编译器我们要保留以前使用的访问策略.
class Sub : public Super { };
Run Code Online (Sandbox Code Playgroud)
不要被误导:这并不意味着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;
}
Run Code Online (Sandbox Code Playgroud)
正如您在示例代码中看到的那样,我们为Sub类提供了一项新功能,它执行了一项重要操作:它从Super类访问存储变量.
如果变量被声明为私有,则不可能.在主函数范围内,变量仍然是隐藏的,所以如果你写了类似的东西:
object.storage = 0;
Run Code Online (Sandbox Code Playgroud)
编译器会通知您它是一个error: 'int Super::storage' is protected.
最后,最后一个程序将产生以下输出:
storage = 101
Run Code Online (Sandbox Code Playgroud)
kin*_*uk4 36
Member in base class : Private Protected Public
Run Code Online (Sandbox Code Playgroud)
继承类型 : 对象继承为:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
Run Code Online (Sandbox Code Playgroud)
yuv*_*uvi 26
1)公共继承:
一个.Derived类中无法访问Base类的私有成员.
湾 Base类的受保护成员在Derived类中保持受保护.
C.Base类的公共成员在Derived类中保持公共状态.
因此,其他类可以通过Derived类对象使用Base类的公共成员.
2)受保护的继承:
一个.Derived类中无法访问Base类的私有成员.
湾 Base类的受保护成员在Derived类中保持受保护.
C.Base类的公共成员也成为Derived类的受保护成员.
因此,其他类不能通过Derived类对象使用Base类的公共成员; 但它们可用于Derived的子类.
3)私人继承:
一个.Derived类中无法访问Base类的私有成员.
湾 Base类的受保护和公共成员成为Derived类的私有成员.
因此,其他类不能通过Derived类对象访问Base类的成员,因为它们在Derived类中是私有的.因此,即使Derived类的子类也无法访问它们.
sbi*_*sbi 20
公共继承模拟IS-A关系.同
class B {};
class D : public B {};
Run Code Online (Sandbox Code Playgroud)
每一个D 都是 B.
私有继承模拟IS-IMPLEMENTED-USING关系(或任何被称为的关系).同
class B {};
class D : private B {};
Run Code Online (Sandbox Code Playgroud)
一个D是不是一个B,但每一个D使用它B的实施.可以通过使用包含来消除私有继承:
class B {};
class D {
private:
B b_;
};
Run Code Online (Sandbox Code Playgroud)
这D也可以使用B,在这种情况下使用它来实现b_.包含是类型之间不那么紧密的耦合而不是继承,所以通常它应该是首选.有时使用包含而不是私有继承不如私有继承方便.这通常是懒惰的蹩脚借口.
我认为没有人知道protected继承模型是什么.至少我还没有看到任何令人信服的解释.
Ark*_*nez 11
如果你从另一个类公开继承,每个人都知道你是继承的,任何人都可以通过基类指针多态地使用它.
如果你继承受保护的只有你的子类可以多态地使用你.
如果你私下继承只有你自己才能执行父类方法.
这基本上象征着其他课程对你与父班关系的了解
受保护的数据成员可以从您的类继承的任何类访问.但是,私人数据成员不能.假设我们有以下内容:
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
Run Code Online (Sandbox Code Playgroud)
从您的扩展程序到此类,引用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
Run Code Online (Sandbox Code Playgroud)
基于这个例子的java ...我认为一个值得千言万语的小桌子:)
摘要:
继承时,您可以(在某些语言中)在特定方向上更改数据成员的保护类型,例如从受保护到公共.
小智 6
基类的私有成员只能由该基类的成员访问.
基类的公共成员可以由该基类的成员,其派生类的成员以及基类和派生类之外的成员访问.
基类的成员以及其派生类的成员可以访问基类的受保护成员.
私人:基地
protected:base + derived
public:base + derived +任何其他成员