web-dev-qa-db-ja.com

特定の関数を非表示にするC ++の方法

継承struct A : public Bがあり、個々の関数をBから非表示にしたいのですが、これは可能ですか?

a宣言でusing BMethodを使用すると逆のことが可能であることを私は知っています。

乾杯

21
lurscher

usingキーワードを使用して、可視性を変更できます

struct A
{
    void method1();
};

struct B: public A
{
    void method2();

    private:
    using A::method1;
};
7
xaviersjs

関数を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

ここに問題があります。これは、リスコフの置換原則の直接の違反になります。つまり、AaBとして機能しなくなります。

B実装を再利用したい場合、解決策は単にそうすることです:

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

private:
  B b;
};

継承を乱用しないでください。代わりに合成を使用してください

27
Matthieu M.

前の回答で説明した方法(構成、プライベート継承、および非プライベート継承であるが、継承されたメソッドがプライベートとして宣言されている)とは別に、別の方法は、継承されたメソッドを明示的に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
_

この明示的な削除方法は、foonotAの仮想の削除されていないメソッドである場合に機能します。 C++ 11標準§10.3/ 16では、派生クラスの削除されたメソッドが基本クラスの仮想の削除されていないメソッドをオーバーライドする場合、この明示的な削除は不正な形式になります。この制限の詳細については、SO質問C++ 11 Delete Overrided Method

13
CodeBricks

それ自体を「非表示」にすることはできませんが、それを呼び出すためにコンパイル時エラーにすることはできます。例:

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

コードパッドの例 エラーあり 、および なし

とはいえ、これが可能であるにもかかわらず、あなたは本当にそれをすべきではありません。あなたはクライアントの地獄を混乱させるでしょう。

編集:これは 仮想関数 (および エラーあり )でも実行できることに注意してください。

8
Billy ONeal

構図を提案している人には...これは物事を進めるための最良の方法ではないかもしれません。私の理解では、リスコフの置換原則は、基本クラスの関数が子で使用される可能性があると述べているだけであり、必ずしもそうあるべきではないということです。たとえば、特定の基本クラスの場合、基本的に同じ操作を実行する複数の関数がありますが、特定のケースが異なります。派生クラスでは、ユーザーのインターフェイスを簡素化するために、これらのパブリック関数を抽象化することができます。これは、プライベート継承を使用できる場所です。基本クラスのユーザーに呼び出させたくない基本クラスの保護された関数があるが、派生クラスにとって非常に貴重な場合は、プライベート継承も必要になる可能性があります。

つまり、必要な場合はプライベート継承を使用しますが、ほとんどの場合、構成が優先されます。

4
It'sPete

さらに別のアプローチがあります。

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を使用して、望ましくないメソッドを除外します。この場合、BクラスのオブジェクトがBInterfaceクラスのオブジェクトであっても、BInterfaceクラスのオブジェクトはAクラスのオブジェクトではないため、リスコフの置換原則に違反することはありません。

3

メソッドがBでプライベートである場合、パブリック継承を使用しても、メソッドは非表示のままになります。

2
DPD

元のメソッドの可視性を変更することはできません。

Struct Aに同じ名前のメソッドを作成し、そのメソッドをプライベートにすることもできますが、struct Aのインスタンスがによって参照されているときにメソッドが呼び出されるのを防ぐことはできません。タイプBの変数。

0
ClosureCowboy

基本クラスでVirtualにして、Childrenでオーバーライドしてみませんか? ( その他のヘルプ

0