c++ public private protected区别




私人,公共和受保护继承的区别 (11)

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


私人的:

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

上市:

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

保护:

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

简而言之:

私人 :基地

保护 :基地+派生

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


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


公共继承建模一个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_ 。 遏制是类型之间的紧密耦合而不是继承,所以通常它应该是优选的。 有时使用遏制而不是私有继承不如私有继承方便。 通常这是懒惰的蹩脚借口。

我不认为有人知道什么是protected继承模型。 至少我还没有看到有说服力的解释。


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

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

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


它与基类的公共成员如何从派生类暴露出来有关。

  • 公共 - >基类的公共成员将公开(通常是默认)
  • 保护 - >基地的公共成员将受到保护
  • 私人 - >基础班级的公共成员将是私人的

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


它基本上是派生类中公共和受保护基类的成员的访问保护。 通过公共继承,派生类可以查看基础的公共和受保护成员。 有了私有继承,它不能。 在受保护的情况下,派生类和派生类可以看到它们。


概要:

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

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


看到这些代码,了解c ++有关继承的特性...我把结果放在最后...希望它有帮助。

#include <iostream>
using namespace std;

class A {
private:
    void pri();
    A(int a);
protected:
    virtual void pro() {}
public:
    void pub1() { cout<<"A.pub1()\n"; }
    virtual void pub2() { cout<<"A.pub2()\n"; }
    virtual void pub3() { cout<<"A.pub3()\n"; }
    virtual void pub4() { cout<<"A.pub4()\n"; }
    virtual void pub5() { cout<<"A.pub5()\n"; }
    virtual void pub6() { cout<<"A.pub6()\n"; }
    virtual void pub7() { cout<<"A.pub7()\n"; }
    virtual void pub8() { cout<<"A.pub8()\n"; }
    void pub9() { cout<<"A.pub9()\n"; }
    virtual void pub10() { cout<<"A.pub10()\n"; }
    void pub11() { cout<<"A.pub11()\n"; }
    explicit A() {}
    virtual ~A() {}
};

class B : public A {
private:
    void pri() { cout<<"B.pri()\n"; }
protected:
    virtual void pub4() { cout<<"B.pub4()\n"; }
    void pub6() { cout<<"B.pub6()\n"; }
public:
    void pro() { cout<<"B.pro() "; B::pri(); }
    void pub1() { cout<<"B.pub1()\n"; }
    void pub2() { cout<<"B.pub2()\n"; }
    void pub5() { cout<<"B.pub5()\n"; }
    virtual void pub7() { cout<<"B.pub7()\n"; }
    virtual void pub8() { cout<<"B.pub8()\n"; }
    virtual void pub9() { cout<<"B.pub9()\n"; }
    void pub10() { cout<<"B.pub10()\n"; }
    void pub11() { cout<<"B.pub11()\n"; }
    explicit B() {}
};

class C : protected B {
public:
    void pub4_() { cout<<"C.pub4_() "; B::pub4(); }
    virtual void pub5() { cout<<"C.pub5()\n"; }
};

class D : private B {
public:
    void pub4_() { cout<<"D.pub4_() "; B::pub4(); }
};

class E : public B {
public:
    virtual void pub4() { cout<<"E.pub4()\n"; }
    virtual void pub7() { cout<<"E.pub7()\n"; }
    virtual void pub8() { cout<<"E.pub8()\n"; }
    virtual void pub9() { cout<<"E.pub9()\n"; }
    virtual void pub10() { cout<<"E.pub10()\n"; }
    virtual void pub11() { cout<<"E.pub11()\n"; }
};

void testClasses() {
    A* ap=new B();
    ap->pub1(); // == A::pub1() //important
    // (new B()).pub1() can't override non-virtual A::pub1() for an A* pointer.
    ap->pub2(); // == B::pub2() //important
    // (new B()).pub1() can override virtual A::pub1() for an A* pointer.
    B b;
    b.A::pub1();
    b.pro();
    B* bp=new B;
    bp->pub3();
    C c;
    //c.pub3(); //error
    //c.pub4(); //error
    c.pub4_();
    c.pub5();
    D d;
    //d.pub3(); //error
    //d.pub4(); //error
    d.pub4_();
    E e;
    //e.pub4(); //error
    delete ap;
    ap = new E();
    ap->pub4();
    ap->pub5();
    ap->pub6();
    ap->pub7();
    delete bp;
    bp = new E();
    e.pub8();
    e.A::pub8();
    e.B::A::pub8();
    e.B::pub8();
    ap->pub8();
    bp->pub8();
    e.pub9();
    e.A::pub9();
    e.B::A::pub9();
    e.B::pub9();
    ap->pub9(); // important
    bp->pub9();
    e.pub10();
    e.A::pub10();
    e.B::A::pub10();
    e.B::pub10();
    ap->pub10(); // important
    bp->pub10(); // very important... eventhough B::pub10() is non-virtual,
                 // bp->pub10() != b.pub10();
    e.pub11();
    e.A::pub11();
    e.B::A::pub11();
    e.B::pub11();
    ap->pub11();
    bp->pub11();
    delete ap;
    delete bp;
    return;
}

int main() {
    testClasses();
    return 0;
}









/////////////////////////////////////////
........
Result :
........

A.pub1()
B.pub2()
A.pub1()
B.pro() B.pri()
A.pub3()
C.pub4_() B.pub4()
C.pub5()
D.pub4_() B.pub4()
E.pub4()
B.pub5()
B.pub6()
E.pub7()
E.pub8()
A.pub8()
A.pub8()
B.pub8()
E.pub8()
E.pub8()
E.pub9()
A.pub9()
A.pub9()
B.pub9()
A.pub9()
E.pub9()
E.pub10()
A.pub10()
A.pub10()
B.pub10()
E.pub10()
E.pub10()
E.pub11()
A.pub11()
A.pub11()
B.pub11()
A.pub11()
B.pub11()

限制继承的可见性将使代码无法看到某个类继承另一个类:从派生类到基类的隐式转换将不起作用,并且从基类到派生类的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风格强制转换允许以定义和安全的方式将派生类转换为受保护的或私有的基类,并且也可以投射到其他方向。 应该不惜一切代价避免这种情况,因为它可以使代码依赖于实现细节 - 但是如果有必要,您可以使用这种技术。


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


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

关于保护和私有继承的使用,你可以here阅读。





access-specifier