开发者

How to publicly inherit from a base class but make some of public methods from the base class private in the derived class?

开发者 https://www.devze.com 2023-01-02 17:49 出处:网络
For example, class Base has two public methods: foo() and bar(). Class Derived is inherited from开发者_开发百科 class Base. In class Derived, I want to make foo() public but bar() private. Is the foll

For example, class Base has two public methods: foo() and bar(). Class Derived is inherited from开发者_开发百科 class Base. In class Derived, I want to make foo() public but bar() private. Is the following code the correct and natural way to do this?

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     void bar();
};


Section 11.3 of the C++ '03 standard describes this ability:

11.3 Access declarations
The access of a member of a base class can be changed in the derived class by mentioning its qualified-id in the derived class declaration. Such mention is called an access declaration. The effect of an access declaration qualified-id ; is defined to be equivalent to the declaration using qualified-id

So there are 2 ways you can do it.

Note: As of ISO C++ '11, access-declarations (Base::bar;) are prohibited as noted in the comments. A using-declaration (using Base::bar;) should be used instead.

1) You can use public inheritance and then make bar private:

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : public Base {
private:
    using Base::bar;
};

2) You can use private inheritance and then make foo public:

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : private Base {
public:
    using Base::foo;
};

Note: If you have a pointer or reference of type Base which contains an object of type Derived then the user will still be able to call the member.


There is really no way to do what you want because if you derive publicly from Base, a user of the class will always be able to:

Derived d;
Base& b = d;
b.bar();

It isn't "correct or natural" to make public base class functions inaccessible in a class derived publicy from the base class; instead, the base class interface should be refactored such that those functions are not public or are split into a separate class.


First, you have to understand what you want to do from the OOP perspective. There are two completely different types of inheritance:

  1. Inheritance of Interface. It is when you do implement in Java or other languages that have interfaces as standalone entities, it is also happens when you publically inherit from an empty abstract class in C++. Here you don't care about code at all but want to tell your compiler and everyone using you base/derived classes that this derived class is a special kind of you base class, it has all the properties of base class, it behaves exactly as base class does to the extent visible by the user of it, and can be used instead of the base class in any algorithms.

  2. Inheritance of the code. You have a piece of code in base class that you want to reuse in your derived class. Base class and derived class does not have to be related in any way, you just want to reuse code and that is it.

Public inheritance in C++ is the mix of both kinds, you get interface inheritance and you get code inheritance as well. Private inheritance is a different kind of beasts, you get only code inheritance, users of your derived class can not use it instead of base class and from the user perspective base and derived classes have no relation what-so-ever.

struct Base {};
struct PublicDerived : public Base {};
struct PrivateDerived: private Base {};

Base * base; PublicDerived * public_derived; PrivateDerived * private_derived;

base = public_derived; //good
base = private_derived; //compilation error.

Since you want to change the interface, you shouldn't go with public inheritance, by changing the interface you effectively saying that those two classes have different behavior and can not be used interchangeably. So what you really want is privately inherit and then make all the methods you want public and not the other way around.


According to the Liskov Substitution Principle, public inheritance should model "is-a." What you are saying with Derived publicly inheriting from Base is that wherever Base object is required, an object of type Derived will do.

If you requre Derived to hide some operations that are available for Base, then what you are modeling is something other than "is-a," and public inheritance is not the correct tool.

What you want is either private inheritance or composition, as other answers have detailed.


Let's say you have this:

class Foo{
public:
    void method1();
    void method2();
    void notGonnaSeeIt();
 private:
    //stuff
 };

To wrap it effectively you can either do a private inheritance and pass the methods you want to a public declaration like Brian suggested:

class Bar : private Foo{
    void methodA(){ method1(); }
    void methodB(){ method2(); }
    //more stuff
};

or you can wrap it with a decorator

template<class T>
class Bar{
public:
    Bar(T *_input) : m_Input(_input){}
    void methodA() { m_Input->method1(); }
    void methodB() { m_Input->method2(); }
    //whatever else you need/want
private:
    T* m_Input;
};

Personally, I prefer the template way as it allows you to do the same thing with any class which inherits from Foo.


If you don't need to treat it as the base class later and only need some functions of the base class, you could use composition rather than inheritance? (C# is my first language, but you get the idea)

class Base {
    public void foo();
    public void bar();
};

class Derived {
    private Base _base;

    public void bar() {
        _base.bar();
    }
};


with C++ 11 you could do the following:

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     using Base::bar;  

};

This ensures that Base::bar() is not accessible from outside the Derived class. It's ofcourse still accessible from outside the Base class.

0

精彩评论

暂无评论...
验证码 换一张
取 消