C++ 中的公共和私有继承

发布于 2024-10-10 21:44:21 字数 90 浏览 6 评论 0原文

从文献中我们知道,对于公共继承,子类(子类)的对象也可以被视为基类(超类)的对象。当继承是protected或private时,为什么子类的对象不能被视为超类的对象?

As we know from the literature for the public inheritance the object of child class (sub-class) also can be considered as the object of base class (super-class). Why the object of the sub-class can’t be considered as an object of super-class, when the inheritance is protected or private?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

未央 2024-10-17 21:44:21

因为你看不到它:

class Base
{
    public: virtual ~Base() {}
};

class PublicDerived: public Base
{    };

class PrivateDerived: private Base
{    };

int main()
{
    PublicDerived   publicD;
    PrivateDerived  privateD;

    Base&           base1 = publicD;
    Base&           base2 = privateD; // ERROR
} 

所以你不能在可以使用 Base 对象的地方使用 PrivateDerived 对象。
所以它永远不会表现得像基类对象。

Because you can't see it:

class Base
{
    public: virtual ~Base() {}
};

class PublicDerived: public Base
{    };

class PrivateDerived: private Base
{    };

int main()
{
    PublicDerived   publicD;
    PrivateDerived  privateD;

    Base&           base1 = publicD;
    Base&           base2 = privateD; // ERROR
} 

So you can not use a PrivateDerived object where a Base object could be used.
So it will never act like a Base class object.

掌心的温暖 2024-10-17 21:44:21

一般来说,您会在文献中(以及此处的其他答案)发现 protected/private 继承意味着该类不能用作 base 。事实(其他一些答案暗示了这一点)是,只有继承的可见性受到操作的影响。 派生一个类,即使外部代码无法看到它。

任何 friend 或类都能够利用这种关系:

struct base {
   virtual void foo() { std::cout << "base" << std::endl; }
};
void take_base( base& b ) {}
class derived : base // private {
   friend base& to_base( derived& );
   virtual void foo() { std::cout << "derived" << std::endl; }
public:
   base & as_base() { return *this; }
   void call_function() { take_base(*this); } // ok: inside derived, it knows that it is
                                              // in fact a base
};
base& to_base( derived& d ) {
   return d;
}
int main() {
   derived d;
   //d.foo();      // error
   //take_base(d); // error
   take_base( d.as_base() ); // ok, the conversion is performed internally where
                             // access is granted: print "derived"
   take_base( to_base(d) );  // ok, the conversion is performed in a friend function
                             // that has access: print "derived"
}

现在,虽然技术上是这样,但从语义上讲,当您使用 private 继承时,您试图建模的不是一种is-a,而是一种implemented-in-terms-of关系。这是重要的部分:在阅读代码时,如果您看到private继承,您不应该考虑is-a,而是implemented-in-terms-of。

In general you will find in literature (and in other answers here) that protected/private inheritance imply that the class cannot be used as a base. The fact (some other answer hints into this) is that only the visibility of the inheritance is affected by the operation. The derived class is a base class, even if external code cannot see it.

Any friend or the class will be able to make use of that relationship:

struct base {
   virtual void foo() { std::cout << "base" << std::endl; }
};
void take_base( base& b ) {}
class derived : base // private {
   friend base& to_base( derived& );
   virtual void foo() { std::cout << "derived" << std::endl; }
public:
   base & as_base() { return *this; }
   void call_function() { take_base(*this); } // ok: inside derived, it knows that it is
                                              // in fact a base
};
base& to_base( derived& d ) {
   return d;
}
int main() {
   derived d;
   //d.foo();      // error
   //take_base(d); // error
   take_base( d.as_base() ); // ok, the conversion is performed internally where
                             // access is granted: print "derived"
   take_base( to_base(d) );  // ok, the conversion is performed in a friend function
                             // that has access: print "derived"
}

Now, while technically this is the case, semantically when you use private inheritance you are trying to model not an is-a but rather a implemented-in-terms-of relationship. This is the important part: while reading code, if you see private inheritance you should not think on is-a but implemented-in-terms-of.

榕城若虚 2024-10-17 21:44:21

简而言之,因为私有继承是实现的继承,而不是接口的继承。私有子类Derived对象不是Base,但是是根据Base实现的代码>. Base 的公共和受保护成员对于 Derived 可见,但它们变为私有,因此外部世界无法访问。因此,私有继承可以被认为是一种特殊的组合形式,实际上在实践中很少需要这种形式。 (受保护的继承实际上从来都不是——事实上,甚至可能连 Bjarne Stroustrup 也不知道受保护的继承意味着什么。)

In brief, because private inheritance is inheritance of implementation, not that of interface. A private subclass Derived object is not a Base, but is implemented in terms of Base. The public and protected members of Base are visible for Derived, but they become private, thus inaccessible for the outside world. Thus private inheritance can be thought of as a special form of composition, which is in fact rarely needed in practice. (And protected inheritance is practically never - in fact probably even Bjarne Stroustrup doesn't know what protected inheritance means.)

月亮坠入山谷 2024-10-17 21:44:21

当考虑该机制如何工作时,“为什么”很简单:因为受保护和私有继承意味着以这种方式工作。

但这可能不足以回答问题的意图。您可能会问“如果不能将生成的对象用作基类的实例,为什么拥有私有继承和受保护继承?”

嗯,非公共继承旨在促进两个类之间的“根据...实现”关系(而公共继承则促进“is-a”关系)。换句话说,您打算重用部分或全部基类功能来为您自己的消费者提供服务。

这种情况几乎总是通过聚合而不是继承(即,拥有“基”类的成员对象)来更好地实现,而且我什至可以说,非公共继承是更好的东西。

请查看,以获取对上述内容进行扩展的较长文章。

更新:正如下面的评论者所说,在某些(诚然罕见)的情况下,非公共继承提供了否则不可能实现的架构功能机制。请务必阅读它们,因为探索语言的边缘可能会很有启发。但无论如何,尽量少做。

The "why" is simple when considering how the mechanism works: because protected and private inheritance are meant to work that way.

This is probably not enough to answer the question's intent though. You might ask "and why have private and protected inheritance if you can't use the resulting objects as instances of the base class?"

Well, non-public inheritance is meant to facilitate the "is implemented in terms of" relationship between two classes (whereas public inheritance facilitates the "is-a" relationship). In other words, you intend to reuse part or all of the base class functionality to provide services to your own consumers.

This scenario is almost always better implemented by aggregation instead of inheritance (i.e., having a member object of the "base" class), and I would go so far as to say that non-public inheritance is something better left alone.

Take a look at this for a longer write-up that expands on the above.

Update: as the commenters below state, there are some (admittedly rare) cases where non-public inheritance provides the mechanism for architectural functionality that would not otherwise be possible. Do read them, as exploring the edges of a language can be quite enlightening. But try to do it as little as you can anyway.

剪不断理还乱 2024-10-17 21:44:21

public 继承服务于 is-a 关系的目的。也就是说:

class A {};
class B : public A {};

Class B is a version of class A.

private继承服务于has-a关系的目的。您可以使用容器模型使用私有继承编写几乎任何类:

class A {};
class B : private A {};

可以重写(并且为了清晰起见,通常应该重写):

class A {};
class B
{
private:
    A a;
};

protected继承类似于private,但实际上几乎不应该使用(Scott Meyers 和 Herb Sutter 都在各自的书中给出了这样做的原因)。

public inheritance serves the purpose of the is-a relationship. That is:

class A {};
class B : public A {};

Class B is a version of class A.

private inheritance serves the purpose of the has-a relationship. You can write almost any class using private inheritance using a container model instead:

class A {};
class B : private A {};

can be rewritten (and more often than not, should be rewritten for clarity):

class A {};
class B
{
private:
    A a;
};

protected inheritance is similar to private, but in reality should almost never be used (Scott Meyers and Herb Sutter both give reasons for this in their respective books).

孤单情人 2024-10-17 21:44:21

您可以将公共/受保护/私有继承视为任何类成员的可访问性:这只是“您想要显示多少”的问题。

私有(或受保护,以稍微不同的方式)继承是一种不向外界显示的关系。因此,您不能将派生类型的对象视为其私有基,因为您无法“看到”这种关系是否存在。

You can think of public / protected / private inheritance like accessibility for any class member : it a matter of 'how much you want to show'.

A private (or protected, in a slightly different way) inheritance is a relationship which is not shown the outside world. As such, you can't treat an object of a derived type as its private base, because you don't get to "see" that this relationship even exists.

思念绕指尖 2024-10-17 21:44:21

为什么子类的对象不能
被视为一个对象
超类,当继承是
受保护还是私有?

它当然可以被视为超类的对象。但是,这种考虑仅限于(通过 public/protected/private 继承修饰符),但仅限于本身(私有继承)或其子类(受保护的继承)。

所有外部对象都不允许被视为类,类似于它们不允许访问受保护或私有方法或变量。如果表达得当的话,这个类比是相当恰当的。

因此,类本身、它的子类(和朋友)可以将其视为一种 is-a 关系,但外部世界不允许这样做。

以下代码显示了这一点:

class Base {
    public: virtual ~Base() {}
};

class PublicDerived: public Base
{ };

class ProtectedDerived: protected Base {
    void test() {
        Base* base2 = this; // OK
    }
};

class ProtectedSubClass: public ProtectedDerived {
    void test() {
        Base* base2 = this; // OK
    }
};

class PrivateDerived: private Base {
    void test() {
        Base* base2 = this; // OK
    }
};

class PrivateSubClass: public PrivateDerived {
    void test() {
        Base* base2 = this; // Error (line 28)
    }
};

int main()
{
    PublicDerived   publicD;
    ProtectedDerived protectedD;
    PrivateDerived  privateD;

    Base* base1 = &publicD;
    Base* base2 = &protectedD; // Error (line 39)
    Base* base3 = &privateD; // Error (line 40)
} 

请注意,xxxSubClass 类如何从其超类派生并不重要。 这都是关于超类如何从 Base 派生,这是应该的。

编译器适当地抱怨:

inherit.cpp(28) : error C2247: 'Base' not accessible because 'PrivateDerived' uses 'private' to inherit from 'Base'
        inherit.cpp(1) : see declaration of 'Base'
        inherit.cpp(20) : see declaration of 'PrivateDerived'
        inherit.cpp(1) : see declaration of 'Base'
inherit.cpp(29) : error C2243: 'type cast' : conversion from 'PrivateSubClass *const ' to 'Base *' exists, but is inaccessible
inherit.cpp(39) : error C2243: 'type cast' : conversion from 'ProtectedDerived *' to 'Base *' exists, but is inaccessible
inherit.cpp(40) : error C2243: 'type cast' : conversion from 'PrivateDerived *' to 'Base *' exists, but is inaccessible

Why the object of the sub-class can’t
be considered as an object of
super-class, when the inheritance is
protected or private?

It can certainly be considered an object of the super-class. However, such consideration is restricted (by the public/protected/private inhertiance modifier) to but only by itself (private inheritance) or it's sub-classes (protected inheritance).

All external objects are not allowed to considered the class as such, similar to how they not allowed to access protected or private methods or variables. The analogy is rather fitting, if expressed properly.

So, the class itself, its subclasses (and friends) can see this as an is-a relationship, but the outside world is not permitted to do so.

The following code shows this in action:

class Base {
    public: virtual ~Base() {}
};

class PublicDerived: public Base
{ };

class ProtectedDerived: protected Base {
    void test() {
        Base* base2 = this; // OK
    }
};

class ProtectedSubClass: public ProtectedDerived {
    void test() {
        Base* base2 = this; // OK
    }
};

class PrivateDerived: private Base {
    void test() {
        Base* base2 = this; // OK
    }
};

class PrivateSubClass: public PrivateDerived {
    void test() {
        Base* base2 = this; // Error (line 28)
    }
};

int main()
{
    PublicDerived   publicD;
    ProtectedDerived protectedD;
    PrivateDerived  privateD;

    Base* base1 = &publicD;
    Base* base2 = &protectedD; // Error (line 39)
    Base* base3 = &privateD; // Error (line 40)
} 

Note that it doesn't matter how the xxxSubClass-classes derive from their super-classes. It's all about how the super-classes derive from Base, which is as it should be.

The compiler complains appropriately:

inherit.cpp(28) : error C2247: 'Base' not accessible because 'PrivateDerived' uses 'private' to inherit from 'Base'
        inherit.cpp(1) : see declaration of 'Base'
        inherit.cpp(20) : see declaration of 'PrivateDerived'
        inherit.cpp(1) : see declaration of 'Base'
inherit.cpp(29) : error C2243: 'type cast' : conversion from 'PrivateSubClass *const ' to 'Base *' exists, but is inaccessible
inherit.cpp(39) : error C2243: 'type cast' : conversion from 'ProtectedDerived *' to 'Base *' exists, but is inaccessible
inherit.cpp(40) : error C2243: 'type cast' : conversion from 'PrivateDerived *' to 'Base *' exists, but is inaccessible
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文