是什么区别
public
,private
以及protected
在继承C ++?
我在SO上发现的所有问题都与特定情况有关。
是什么区别
public
,private
以及protected
在继承C ++?
我在SO上发现的所有问题都与特定情况有关。
Answers:
为了回答这个问题,我想先用自己的语言描述成员的访问者。如果您已经知道这一点,请跳到标题“下一个:”。
有三个访问器,我所知道的: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
是如何像硬编码方式组成type的匿名成员的SomeBase
。像任何其他成员一样,它具有访问说明符,该说明符对外部访问施加相同的控制。
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。这只是访问的问题。
关于受保护和私有继承的用法,您可以在这里阅读。
限制继承的可见性将使代码无法看到某个类继承了另一个类:从派生到基础的隐式转换将不起作用,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并且其类被继承为public,则结果访问为public。
一个例子:
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;
}
已定义的名为Sub的类是Sub类的子类,Super
或者Sub
该类是从Super
该类派生的。该Sub
课程介绍既不是新的变量,也没有新的功能。这是否意味着Sub
该类的任何对象Super
实际上是Super
该类的对象的副本之后,便继承了所有特征?
没有。没有。
如果我们编译下面的代码,除了编译错误说put
和get
方法不可访问外,我们什么都不会得到。为什么?
当我们省略可见性说明符时,编译器会假定我们将应用所谓的私有继承。这意味着所有公共超类组件都变为私有访问,私有超类组件根本无法访问。因此,这意味着不允许您在子类内部使用后者。
我们必须通知编译器我们要保留以前使用的访问策略。
class Sub : public Super { };
不要被误导:这并不意味着Super类的私有组件(例如存储变量)将以某种神奇的方式变成公共组件。私有部分将保持私有,公共部分 将保持公共。
Sub
类的对象可能会执行与从Super
类创建的同级兄弟几乎“相同”的操作。“几乎”是因为作为子类的事实也意味着该类无法访问超类的私有组件。我们无法编写Sub
该类的成员函数,该成员函数将能够直接操作存储变量。
这是一个非常严重的限制。有什么解决方法吗?
是的。
第三个访问级别称为protected。关键字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
它与如何从派生类中公开基类的公共成员有关。
正如litb指出的那样,公共继承是大多数编程语言中都会看到的传统继承。也就是说,它为“ IS-A”关系建模。私有继承是C ++特有的AFAIK,它是一种“在条款中实施”的关系。那就是您想在派生类中使用公共接口,但是不希望派生类的用户有权访问该接口。许多人争辩说,在这种情况下,您应该聚合基类,而不是将基类作为私有基,而应将其作为派生成员,以便重用基类的功能。
Member in base class : Private Protected Public
继承类型 : 对象继承为:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
1)公共继承:
一个。在派生类中无法访问基类的私有成员。
b。基本类的受保护成员在派生类中仍然受保护。
C。基类的公共成员在派生类中保持公共状态。
因此,其他类可以通过Derived类对象使用Base类的公共成员。
2)受保护的继承:
一个。在派生类中无法访问基类的私有成员。
b。基本类的受保护成员在派生类中仍然受保护。
C。基类的公共成员也将成为派生类的受保护成员。
因此,其他类不能通过Derived类对象使用Base类的公共成员。但它们可用于“派生”的子类。
3)私有继承:
一个。在派生类中无法访问基类的私有成员。
b。受保护的基类的公共成员将成为派生类的私有成员。
因此,其他类不能通过派生类对象访问基类的成员,因为它们在派生类中是私有的。因此,即使派生类的子类也无法访问它们。
公共继承为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_
。与继承相比,包含是类型之间的紧密耦合,因此通常应首选。有时使用包容代替私有继承不如私有继承方便。通常这是懒惰的la脚借口。
我认为没有人知道什么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) {} };
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
}