Способ в С++ скрывать определенную функцию

У меня есть наследование struct A : public B, я хочу скрыть отдельные функции из B, возможно ли это?

Я знаю, что обратное возможно с помощью using BMethod в декларации A.

веселит

Ответ 1

Здесь есть проблема: это было бы прямым нарушением Принципа замещения Лискова, а именно A больше не будет действовать как B.

Если вы хотите повторно использовать реализацию B, решение просто для этого:

class A
{
public:
  void foo() { return b.foo(); }
  void bar() { return b.bar(); }
  // ...

private:
  B b;
};

Не злоупотребляйте наследованием, используйте композицию вместо

Ответ 2

Если вы хотите выборочно скрыть функции из B, в первую очередь не стоит использовать публичное наследование.
Используйте частное наследование и выборочно выведите методы из B в область A:

struct B{
   void method1(){};
   void method2(){};
};
struct A : private B{
   using B::method1;
};

A a;
a.method1();
a.method2(); //error method2 is not accesible

Ответ 3

Помимо способов, описанных в предыдущих ответах - состав, частное наследование и неличное наследование, но с унаследованным методом, объявленным private - другим способом, явно указывается delete унаследованный метод:

#include <iostream>

struct A {
    void foo() { std::cout << "foo\n"; }
};

struct B : A {
    void foo() = delete;
};

int main() {
    B b;
    b.foo(); // COMPILER ERROR
}

Хотя вызов b.foo() создает ошибку компилятора, клиентский код все равно может вызывать версию базовых классов путем квалификации с идентификатором базового класса A:

b.A::foo(); // compiles, outputs 'foo' to console

Этот явный способ удаления работает, когда foo не является виртуальным не удаленным методом в A. В С++ 11 Standard §10.3/16 это явное удаление плохо сформировано, когда удаленный метод в производном классе переопределяет виртуальный не удаленный метод базового класса. Для получения дополнительной информации об этом ограничении см. Ответы на вопрос SO С++ 11 Удалить метод переопределения.

Ответ 4

Вы не можете "скрыть это" как таковое, но вы можете сделать это ошибкой времени компиляции, чтобы вызвать его. Пример:

struct A
{
    void AMethod() {}
};

class B : public A
{
    void AMethod() {} //Hides A::AMethod
};

int main()
{
    B myB;
    myB.AMethod(); //Error: AMethod is private
    static_cast<A*>(&myB)->AMethod(); //Ok
    return 0;
}

Примеры кодаже с ошибкой и без.

Все сказанное, несмотря на это, вы действительно не должны этого делать. Вы будете путать ад с клиентами.

EDIT: обратите внимание, что вы также можете сделать это с помощью виртуальных функцийс ошибкой).

Ответ 5

Для тех, кто предлагает композицию... это может быть не самый лучший способ обойти вещи. Мое понимание заключается в том, что Принцип замещения Лискова утверждает только, что существует возможность использования функций из базового класса для ребенка, а не того, что они обязательно должны быть. Например, для определенного базового класса у вас может быть несколько функций, которые по существу выполняют одну и ту же операцию, но для разных конкретных случаев. В производном классе вы можете отбросить эти публичные функции в пользу упрощения пользовательского интерфейса. Здесь можно использовать частное наследование. Частное наследование также может быть необходимо, если у нас есть защищенные функции в базовом классе, которые мы не хотим, чтобы пользователь базового класса вызывал, но был бы неоценим для производного класса.

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

Ответ 6

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

Ответ 7

Существует еще один подход.

class A{
    void f1();
    void f2();
    void f3();
}

class BInterface{
    void f2();
    void f3();
}

class B : public A, BInterface
{
}

BInterface b = new B();
b->f1(); //doesn't work since f1 is not declared in BInterface
b->f2(); //should work
b->f3(); //should work
delete(b);

Используйте BInterface в качестве фильтра для унаследованных классов, чтобы исключить нежелательные методы. Принцип подстановки Лискова не нарушается в этом случае, поскольку объект класса BInterface не является объектом класса A, даже если объект класса B является объектом класса BInterface.

Ответ 8

Невозможно изменить видимость исходного метода.

Вы можете создать метод в struct A с тем же именем и иметь этот метод как закрытый, но это не мешает вызывать метод, когда экземпляр struct A ссылается на переменную тип B.

Ответ 9

Почему бы вам не сделать его виртуальным в базовом классе и переопределить его в своих дочерних элементах? (дополнительная справка)

Ответ 10

Ключевое слово using может использоваться для изменения видимости

struct A
{
    void method1();
};

struct B: public A
{
    void method2();

    private:
    using A::method1;
};