提问



C ++中publicprivateprotected继承有什么区别?我在SO上发现的所有问题都涉及特定案例。

最佳参考


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


我知道有三种访问器:publicprotectedprivate


让:


class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};



  • 所有知道Base的东西也知道Base包含publicMember

  • 只有子(及其子女)知道Base包含protectedMember

  • 除了Base之外没人知道privateMember



通过意识到,我的意思是承认存在,从而能够访问。


下:



公共,私有和受保护的继承也是如此。让我们考虑一个继承自Base的类Base和类Child



  • 如果继承是public,那么所有知道BaseChild的人也会意识到Child继承自Base

  • 如果继承是protected,只有Child及其子女知道他们继承自Base

  • 如果继承是private,除Child以外的任何人都不知道继承。


其它参考1


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


关于受保护和私有继承的使用,你可以在这里阅读。

其它参考2


限制继承的可见性将使代码无法看到某些类继承了另一个类:从派生到基础的隐式转换不会起作用,而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. 实现合条件方面的。基类的用法仅用于实现派生类。对traits有用,如果size很重要(只包含函数的空特性将使用空基类优化)。但是,通常包含是更好的解决方案。字符串的大小是至关重要的,因此这是一个常见的用法


    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样式转换有意允许以定义和安全的方式将派生类转换为受保护的或私有的基类,并且也可以转换到另一个方向。应该不惜一切代价避免这种情况,因为它可以使代码依赖于实现细节 - 但如果有必要,您可以使用这种技术。

其它参考3


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



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


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

其它参考4



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


此表收集组件声明和继承模型的所有可能组合,在完全定义子类时显示对组件的结果访问。





上面的表格按以下方式解释(请看第一行):



  如果某个组件声明公开且其类继承公开,则生成访问公开



一个例子:


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

 class Sub : private Super {};

 class Subsub : public Sub {};


对类 Subsub 中变量pqr的结果访问是



  另一个例子:



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


对类别 Sub 中的变量yz的结果访问是受保护,对于变量x none



  一个更详细的例子:



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的已定义类是SuperSub类的子类,它是从Super类派生的。
Sub类既不引入新变量也不引入新函数。这是否意味着Sub类的任何对象在Super类实际上是Super类'对象的副本之后继承了所有特征?


即可。它没有。


如果我们编译下面的代码,我们将得到的只是编译错误,说putget方法是不可访问的。为什么?


当我们省略可见性说明符时,编译器会假定我们将应用所谓的私有继承。这意味着所有公共超类组件都变成私有访问权限,私有超类组件根本无法访问。因此意味着您不允许在内部使用后者子类。


我们必须告知编译器我们要保留以前使用的访问策略。


class Sub : public Super { };



  不要被误导:它并不意味着Super的私有组件
  class(如存储变量)将变为公共变量
  有点神奇的方式。 私有组件将保持私有公开
  将继续公开



Sub类的对象可能与从Super类创建的兄弟姐妹几乎相同。 Almost因为作为子类的事实也意味着类失去了对超类的私有组件的访问权限。我们不能编写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


Member in base class : Private   Protected   Public   


继承类型:             对象继承为:


Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public

其它参考6


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的子类
class不能访问它们。

其它参考7


公共继承模拟IS-A关系。同


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


每个D 都是 B


私有继承模拟IS-IMPLEMENTED-USING关系(或任何被称为)的关系


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


a D 不 a B,但每个D在其实现中使用其B。可以通过使用包含来消除私有继承:


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


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


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

其它参考8


如果你从另一个类公开继承,那么每个人都知道你是继承的,任何人都可以通过基类指针多态地使用它。


如果你继承受保护,只有你的子类可以多态地使用你。


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


这基本上象征着其他课程对你与父班关系的了解

其它参考9


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


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


从你的扩展到这个类,引用this.myPrivateMember不会工作。但是,this.myProtectedMember将会。这个值仍然是封装的,所以如果我们有一个名为myObj的类的实例化,那么myObj.myProtectedMember不会起作用,所以它在功能上类似于私人数据成员。

其它参考10


概要:



  • 私人:除了班级
  • 之外,没有人能看到它
  • 受保护:私有+派生类可以看到它

  • 公众:世界可以看到它



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

其它参考11


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的例子...我认为一个值得千言万语的小桌子:)

其它参考12


私人:



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


公开:



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


受保护的:



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





简而言之:



私人:基地


受保护:base + derived


公开:base + derived +任何其他成员

其它参考13


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

其它参考14


我找到了一个简单的答案,所以想过将它发布给我以后的参考。


来自链接http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/[90]


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
}