关于继承:为什么C ++允许对公共继承的基本方法进行访问限制?

Why does C++ allow access restrictions on public inherited base methods?

关于"如何从基类公开继承,但在派生类中使来自基类的某些公共方法私有化"的问题?,我有一个后续问题:

我可以理解,C++标准允许派生类放松继承的方法的访问限制,但是我想不出任何合法的用例,在派生类中引入访问限制是有意义的。

根据我对继承概念的理解,如果类派生是公共类基,那么您可以对基做的任何事情也可以用派生来完成。如果不希望派生实现基的接口,则首先不应使用(公共)继承。(实际上,当我在root的th2::fill(double)中遇到这种技术时,它显然是一种继承滥用的情况。)

对于虚拟方法,派生方法中的访问限制也是无用的,因为派生方法的任何用户都可以通过将派生*强制转换为基*来使用它们。

因此,从我有限的C++新手角度来看,这些限制是误导性的(派生程序的程序员可能假设他的虚拟现在保护的方法不被任何其他人调用,事实上它可能是),并且混淆了[我关于公共继承应该意味着什么]。

我有没有丢失一些合法的用例?


从Herb Sutter,大师的# 18周。

Guideline #3: Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected.

零售的答案,请读我的评论写在下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <typeinfo>
#include <memory>

struct Ultimate_base {
    virtual ~Ultimate_base() {}
    void foo() { do_foo(); }
protected:
    // Make this method protected, so the derived class of this class
    // can invoke this implementation
    virtual void do_foo() { std::cout <<"Ultimate_base::foo"; }
};

struct Our_derived : Ultimate_base {
private:
    // Make this method private, so the derived class of this class
    // can't  invoke this implementation
    void do_foo() {
        Ultimate_base::do_foo();
        std::cout <<" Our_derived::foo";
    }
};

struct Derive_from_derive : Our_derived {
private:
    void do_foo() {
        // You can't call below code
        // vvvvvvvvvvvvvvvvvvvvvv
        // Our_derived::do_foo();
        std::cout <<" Derive_from_derive::foo";
    }
};

// This class is marked final by making its destructor private
// of course, from C++11, you have new keyword final
struct Derive_with_private_dtor : Ultimate_base {
private:
    ~Derive_with_private_dtor() {}
};

// You can't have below class because its destructor needs to invoke
// its direct base class destructor
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/*
struct Derive_from_private_dtor : Derive_with_private_dtor {
};
*/


int main() {
    std::unique_ptr<Ultimate_base> p = std::make_unique<Our_derived>();
    p->foo();
    p = std::make_unique<Derive_from_derive>();
    p->foo();
    p.reset(new Derive_with_private_dtor);
}


From my understanding of the concept of inheritance, if class Derived is public class Base, then anything you can do with Base can also be done with Derived.

这不是真的观念传承的;这是polymorphism)的概念。'这是一个statement of the Liskov替换原则。但传承可以用于各种事情在C + + polymorphism超越我。事实上,任何时候你的基地有非虚拟类的数据成员或方法,你是用它inject实施或国家为衍生类的,不只是对polymorphism。如果基础类虚拟方法有NO和NO的虚拟类的析构函数,则不应该(不能)被用来多态。你可以使用一个基础类,告诉他们将永远是"基地instantiated类,或将你曾经使用一个指针的一个基地。这里的的实例:

1
2
3
4
5
template <class T>
struct Foo {
    T double_this() { return 2 * static_cast<T&>(*this).data; }
    T halve_this() { return 0.5 * static_cast<T&>(*this).data; }
};

奇怪的是,这类死亡吗?好的,它可以被用来inject有两个接口到任何类的数据成员和一个所谓的data(和适当的constructor):

1
2
3
4
struct Bar : Foo<Bar> {
    Bar(double x) : data(x) {}
    double data;
};

现在BarGLT方法和halvedouble。本模式称为冰curiously recurring模板模式(CRTP)。注意,我们永远不会再Foo实例化两个或两个网络有一个指针。我们只是使用它提供的接口,非多态。

现在,假如有人想用Foo,只想在他们的double但不halve接口。在这个案例中,它的完全有效,使halve私人的衍生。毕竟,在衍生类看,特别是一些非多态类型,不需要符合两个接口比其他任何我想/文件的作者。

注意,当使用CRTP,基地将typically提供公共类的功能,你会typically inherit publicly。的全部优势(CRTP在这个案例上,你可以直接inject接口;如果你是一个私人的或补充的方法inherit privately你会做的更好FooBar而不是一个成员国的大学。所以它会让更多的普通的东西变成私人的,公共的,而不是"逆向,在这种特殊的情况。