Подтвердить что ты не робот

Как публично наследовать из базового класса, но сделать некоторые из общедоступных методов из базового класса приватными в производном классе?

Например, класс Base имеет два общедоступных метода: foo() и bar(). Класс Derived наследуется от класса Base. В классе Derived я хочу сделать foo() public, но bar() private. Является ли следующий код правильным и естественным способом для этого?

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

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

Ответ 1

В разделе 11.3 стандарта С++ '03 описывается эта возможность:

11.3. Объявления доступа
 Доступ к член базового класса можно изменить в производном классе, указав его Квалифицированный идентификатор в производном классе декларация. Такое упоминание называется объявление доступа. Эффект объявление доступа с квалификацией - id; является определяется как эквивалентное объявление с использованием identified-id

Итак, есть два способа сделать это.

Примечание. Что касается ISO С++ '11, объявления доступа (Base::bar;) запрещены, как указано в комментариях. Вместо этого следует использовать декларацию использования (using Base::bar;).

1) Вы можете использовать общедоступное наследование, а затем сделать bar частным:

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

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

2) Вы можете использовать личное наследование, а затем сделать foo общедоступным:

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

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

Примечание. Если у вас есть указатель или ссылка типа Base, который содержит объект типа Derived, пользователь все равно сможет вызвать его.

Ответ 2

Нет никакого способа сделать то, что вы хотите, потому что, если вы публично выходите из Base, пользователь класса всегда сможет:

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

Это не является "правильным или естественным", чтобы сделать общедоступные функции базового класса недоступными в производной от класса классе из базового класса; вместо этого интерфейс базового класса должен быть реорганизован таким образом, чтобы эти функции не были общедоступными или были разделены на отдельный класс.

Ответ 3

Во-первых, вам нужно понять, что вы хотите сделать с точки зрения ООП. Существует два совершенно разных типа наследования:

  • Наследование интерфейса. Это когда вы выполняете implement на Java или на других языках, которые имеют интерфейсы как автономные объекты, это также происходит, когда вы публично наследуете от пустого абстрактного класса на С++. Здесь вам все равно не нужен код, но вы хотите сообщить своему компилятору и всем, кто использует ваши базовые/производные классы, что этот производный класс является особым типом вашего базового класса, он имеет all свойства базовый класс, он ведет себя точно, поскольку базовый класс делает это настолько, насколько это видно пользователю, и может использоваться вместо базового класса в любых алгоритмах.

  • Наследование кода. У вас есть часть кода в базовом классе, которую вы хотите повторно использовать в производном классе. Базовый класс и производный класс не должны быть связаны каким-либо образом, вы просто хотите повторно использовать код и это он.

Наше наследование в С++ представляет собой сочетание обоих типов, вы получаете наследование интерфейса, и вы также получаете наследование кода. Частное наследование - это другой тип животных, вы получаете наследование кода только, пользователи вашего производного класса не могут использовать его вместо базового класса, а из базы данных пользователя и производных классов не имеют никакого отношения к тому, что -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.

Поскольку вы хотите изменить интерфейс, вы не должны идти с публичным наследованием, изменив интерфейс, который вы фактически говорите, что эти два класса имеют другое поведение и не могут использоваться взаимозаменяемо. Итак, что вы действительно хотите, наследуйте на частном уровне, а затем создайте все методы, которые вы хотите публиковать, а - не наоборот..

Ответ 4

В соответствии с Принцип замены Лискова, наследование наследования должно моделировать "is-a". То, что вы говорите при Derived публичном наследовании от Base, заключается в том, что везде, где требуется объект Base, будет создан объект типа Derived.

Если вы запрашиваете Derived, чтобы скрыть некоторые операции, доступные для Base, то то, что вы моделируете, является чем-то иным, чем "is-a", а публичное наследование не является правильным инструментом.

То, что вы хотите, - это либо частное наследование, либо состав, как и другие ответы.

Ответ 5

Скажем, у вас есть это:

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

Чтобы эффективно обернуть его, вы можете либо сделать частное наследование, либо передать методы, которые вы хотите публичному объявлению, например Брайан:

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

или вы можете обернуть его декоратором

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;
};

Лично я предпочитаю шаблон, так как он позволяет делать то же самое с любым классом, который наследует от Foo.

Ответ 6

Если вам не нужно рассматривать его как базовый класс позже и нужны только некоторые функции базового класса, вы можете использовать композицию, а не наследование? (С# - мой первый язык, но вы понимаете)

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

class Derived {
    private Base _base;

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