web-dev-qa-db-ja.com

非静的関数を含むC ++オーバーロード静的関数

関数がFoo::print()で静的に呼び出されるか、Foo foo; foo.print();のインスタンスから呼び出されるかに応じて、2つの異なるものを出力したいと思います。

編集:これは確かに機能しないクラス定義です。すでに数人が回答しています。

class Foo {
    string bla;
    Foo() { bla = "nonstatic"; }

    void print() { cout << bla << endl; }
    static void print() { cout << "static" << endl; }
};

しかし、この効果を達成するための良い方法はありますか?基本的に、私はしたいと思います:

if(this is a static call)
    do one thing
else
    do another thing

別の言い方をすると、PHPが*this変数は、関数が静的に呼び出されるかどうかを決定するために定義されているかどうかを示します。 C++には同じ機能がありますか?

37
Alan Turing

いいえ、それは規格によって直接禁止されています:

ISO 14882:2003 C++ Standard 13.1/2 –オーバーロード可能な宣言

特定の関数宣言はオーバーロードできません:

  • 戻りの型のみが異なる関数宣言はオーバーロードできません。
  • 同じ名前と同じパラメーター型のメンバー関数宣言は、それらがstaticメンバー関数宣言(9.4)である場合はオーバーロードできません。

...

[例:

class X {
    static void f();
    void f();                // ill-formed
    void f() const;          // ill-formed
    void f() const volatile; // ill-formed
    void g();
    void g() const;          // OK: no static g
    void g() const volatile; // OK: no static g
};

-例を終了]

...

さらに、インスタンスで静的関数を呼び出すことができるため、いずれにしてもあいまいになります。

ISO 14882:2003 C++ Standard 9.4/2 –静的メンバー

クラスsの静的メンバーXは、qualified-idX::sを使用して参照できます。 ; static memberを参照するためにクラスメンバーアクセス構文(5.2.5)を使用する必要はありません。 staticメンバーは、クラスメンバーアクセス構文を使用して参照できます。その場合、object-expressionが評価されます。 [例:

class process {
public:
        static void reschedule();
}
process& g();
void f()
{
        process::reschedule(); // OK: no object necessary
        g().reschedule();      // g() is called
}

-例を終了]

...

だから、あなたが持っているものには曖昧さが存在します:

class Foo
{
public:
    string bla;
    Foo() { bla = "nonstatic"; }
    void print() { cout << bla << endl; }
    static void print() { cout << "static" << endl; }
};

int main()
{
    Foo f;
    // Call the static or non-static member function?
    // C++ standard 9.4/2 says that static member
    // functions are callable via this syntax. But
    // since there's also a non-static function named
    // "print()", it is ambiguous.
    f.print();
}

メンバー関数が呼び出されているインスタンスを確認できるかどうかという質問に対処するために、thisキーワードがあります。 thisキーワードは、関数が呼び出されたオブジェクトを指します。ただし、thisキーワードは常にオブジェクトを指します。つまり、NULLになることはありません。したがって、関数が静的に呼び出されているのか、PHP以外で呼び出されているのかを確認することはできません。

ISO 14882:2003 C++ Standard 9.3.2/1 – thisポインター

非静的(9.3)メンバー関数の本体では、キーワードthisは非値の式であり、その値は関数が呼び出されるオブジェクトのアドレスです。

57
In silico

絶対に許可されていません。私はこれを達成するためのきれいな方法を見ていません。この方法で解決したい問題は何ですか?

2
Janick Bernet

正確にそれを行うことはできません。 インシリコの答え を参照してください。

ただし、Foo::print()Foo foo; print(foo);に異なる処理をさせることができます。 (void print(Foo& foo)を_class Foo_と同じ名前空間で定義します。ADLによって検出されます)。

いずれにしても、これは良い考えではありません。名前が非常に似ている2つの関数があり、それらはまったく異なることを行うため、優れた設計原則に違反しています。

1
Ben Voigt

戻り値の型に基づいてオーバーロードすることはできないため、答えはノーです。

確かにクラスに静的メソッドを含めることはできますが、以下を含めることはできません。

static void foo();
void foo();

同じメソッドシグネチャがあるためです。

編集:なぜこれを行いたいのか、そしてメンバー変数にアクセスしたいのかというコメントを見ました。これを行う必要があります:

static void print(Foo f);
void print();
....
static void Foo::print(Foo f)
{
    int a = f.a;
    // do something with a
}

(またはFooなどでゲッターとセッターを作成しますが、それが一般的な考えです)

1
Brian Roach