1143

C++public中的、privateprotected继承 有什么区别?

我在 SO 上发现的所有问题都涉及特定案例。

4

16 回答 16

1623
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。这只是访问的问题。

关于受保护和私有继承的使用,您可以在此处阅读。

于 2009-09-03T11:27:56.297 回答
1156

为了回答这个问题,我想先用我自己的话来描述一下成员的访问者。如果您已经知道这一点,请跳到标题“下一个:”。

我知道三个访问器publicprotectedprivate

让:

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知道继承。
于 2009-05-13T20:49:37.733 回答
123

限制继承的可见性将使代码无法看到某个类继承了另一个类:从派生到基的隐式转换不起作用,static_cast从基到派生的隐式转换也不起作用。

只有类的成员/朋友才能看到私有继承,只有成员/朋友和派生类才能看到受保护的继承。

公共继承

  1. IS-A 继承。一个按钮就是一个窗口,在任何需要窗口的地方,也可以传递一个按钮。

    class button : public window { };
    

受保护的继承

  1. 受保护的实施条款。很少有用。用于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!
      }
    };
    

私有继承

  1. 按条款实施。基类的使用仅用于实现派生类。对特征有用,如果大小很重要(只包含函数的空特征将利用空基类优化)。不过,通常遏制是更好的解决方案。字符串的大小很关键,所以这里经常用到

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

公共成员

  1. 总计的

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. 访问器

    class window {
    public:
        int getWidth() const;
    };
    

受保护成员

  1. 为派生类提供增强的访问权限

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

私人会员

  1. 保留实施细节

    class window {
    private:
      int width;
    };
    

请注意,C 风格的强制转换故意允许以定义和安全的方式将派生类强制转换为受保护或私有基类,也可以强制转换为另一个方向。应该不惜一切代价避免这种情况,因为它会使代码依赖于实现细节——但如果有必要,您可以利用这种技术。

于 2009-09-03T16:04:21.027 回答
84

这三个关键字也用在完全不同的上下文中来指定可见性继承模型

该表收集了组件声明和继承模型的所有可能组合,展示了子类完全定义后对组件的访问。

在此处输入图像描述

上表解释如下(看第一行):

如果一个组件被声明public并且它的类被继承public,则结果访问public

一个例子:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

对Subsub类中的变量p,q的结果访问是noner

另一个例子:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

对变量的结果访问yz在类Sub中是受保护的,而对变量的访问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 类的私有组件(如存储变量)将以某种神奇的方式变成公共组件。私有组件将保持私有公共 将保持公开

类的对象可以做“几乎”与从类中Sub创建的兄弟姐妹一样的事情。“几乎”是因为作为子类的事实也意味着该类无法访问超类的私有组件。我们不能编写能够直接操作存储变量的类的成员函数。SuperSub

这是一个非常严重的限制。有什么解决方法吗?

的。

第三个访问级别称为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
于 2015-06-07T16:56:41.690 回答
69

它与基类的公共成员如何从派生类公开有关。

  • public -> 基类的公共成员将是公共的(通常是默认的)
  • protected -> 基类的公共成员将受到保护
  • private -> 基类的公共成员将是私有的

正如 litb 所指出的,公共继承是您将在大多数编程语言中看到的传统继承。也就是说,它模拟了“IS-A”关系。私有继承是 C++ 特有的 AFAIK,是一种“在条款中实现”的关系。那就是您想在派生类中使用公共接口,但不希望派生类的用户有权访问该接口。许多人认为,在这种情况下,您应该聚合基类,而不是将基类作为私有基类,而是在派生的成员中创建,以便重用基类的功能。

于 2009-05-13T20:49:19.607 回答
37
Member in base class : Private   Protected   Public   

继承类型 :             对象继承为

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public
于 2010-09-09T05:25:38.283 回答
28

1)公共继承

一种。在派生类中无法访问基类的私有成员。

湾。Base 类的受保护成员在 Derived 类中保持受保护。

C。Base 类的公共成员在 Derived 类中仍然是公共的。

因此,其他类可以通过派生类对象使用基类的公共成员。

2)受保护的继承

一种。在派生类中无法访问基类的私有成员。

湾。Base 类的受保护成员在 Derived 类中保持受保护。

C。Base 类的公共成员也成为 Derived 类的受保护成员。

所以,其他类不能通过派生类对象使用基类的公共成员;但它们可用于 Derived 的子类。

3)私人继承

一种。在派生类中无法访问基类的私有成员。

湾。基类的受保护和公共成员成为派生类的私有成员。

因此,其他类不能通过派生类对象访问基类的任何成员,因为它们在派生类中是私有的。因此,即使派生类的子类也无法访问它们。

于 2016-05-26T04:42:05.147 回答
20

公共继承对 IS-A 关系建模。和

class B {};
class D : public B {};

每一个D 都是一个 B

私有继承对 IS-IMPLEMENTED-USING 关系(或任何所谓的)建模。和

class B {};
class D : private B {};

aD不是a ,但每个都其实现中使用它。私有继承总是可以通过使用包含来消除:BDB

class B {};
class D {
  private: 
    B b_;
};

D也可以使用 来实现B,在这种情况下使用它的b_. 与继承相比,包含在类型之间的耦合不那么紧密,因此通常应该首选它。有时使用包含而不是私有继承不如私有继承方便。这通常是懒惰的一个蹩脚的借口。

我认为没有人知道protected继承模型是什么。至少我还没有看到任何令人信服的解释。

于 2009-09-03T12:34:26.367 回答
10

如果您从另一个类公开继承,那么每个人都知道您正在继承,并且任何人都可以通过基类指针多态地使用您。

如果您受保护地继承,则只有您的子类才能多态地使用您。

如果你私有继承,只有你自己能够执行父类方法。

这基本上象征着其他班级对您与父班级的关系的了解

于 2009-09-03T11:27:55.203 回答
10
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

基于this example for java...我认为一张价值一千字的小桌子:)

于 2015-05-09T23:03:59.067 回答
9

从您的类继承的任何类都可以访问受保护的数据成员。但是,私有数据成员不能。假设我们有以下内容:

class MyClass {
    private:
        int myPrivateMember;    // lol
    protected:
        int myProtectedMember;
};

在您对此类的扩展中,引用this.myPrivateMember将不起作用。不过,this.myProtectedMember会。该值仍然是封装的,所以如果我们有一个名为 的类的实例化myObj,那么myObj.myProtectedMember它将不起作用,因此它在功能上类似于私有数据成员。

于 2009-05-13T20:57:10.703 回答
7

概括:

  • 私人:除了班级内没有人可以看到它
  • 受保护:私有+派生类可以看到
  • 公众号:全世界都能看到

继承时,您可以(在某些语言中)在某个方向更改数据成员的保护类型,例如从受保护到公共。

于 2009-05-13T20:58:28.140 回答
7

私人的:

基类的私有成员只能由该基类的成员访问。

上市:

基类的公共成员可以被该基类的成员、其派生类的成员以及基类和派生类之外的成员访问。

受保护:

基类的受保护成员可以由基类的成员及其派生类的成员访问。


简而言之:

私人:基地

受保护:基础+派生

public : 基础 + 派生 + 任何其他成员

于 2010-01-06T14:04:59.367 回答
6

我尝试使用下面的图片来解释继承。

主要要点是父类的私有成员永远不能从派生/子类直接访问,但您可以使用父类的成员函数来访问父类的私有成员。私有变量始终存在于派生类中,但派生类无法访问它。就像他们的一样,但你不能用自己的眼睛看到,但如果你问家长班的某个人,那么他可以向你描述。 继承映射 cpp

于 2020-09-22T18:29:04.807 回答
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
}
于 2015-02-24T10:05:09.517 回答
3

它本质上是对派生类中基类的公共和受保护成员的访问保护。使用公共继承,派生类可以看到基类的公共和受保护成员。使用私有继承,它不能。使用受保护的,派生类和从其派生的任何类都可以看到它们。

于 2009-05-13T20:51:43.597 回答