7

非静的メンバー関数のみが仮想になることができることを理解していると言うことから始めますが、これが私が望むものです:

  1. インターフェイスを定義する基本クラス: 基本クラス ポインターを使用して関数にアクセスできます。

  2. メモリ管理の目的で (これは RAM が制限された組み込みシステムです)、オーバーライド関数を静的に割り当てる必要があります。静的関数を使用すると、関数内でデータを操作する方法に制約が生じるという結果を受け入れます。

    私の現在の考えは、実際には静的な関数のラッパーにすることで、軽いオーバーロード関数を保持できるということです。

デザインを再考する必要があると言うのはご遠慮ください。これが私が質問をしている理由です。C を使用してコールバックを使用した方がよいと私に言いたい場合は、オブジェクト指向アプローチを使用する際の落とし穴を説明する読み物を教えてください。私が列挙した要件を満たすオブジェクト指向設計パターンはありますか?

4

4 に答える 4

7

私が列挙した要件を満たすオブジェクト指向設計パターンはありますか?

はい、昔ながらの仮想関数です。あなたの望みは「静的に割り当てられるオーバーライド関数」です。仮想関数静的に割り当てられます。つまり、関数を実装するコードは一度だけ存在し、コンパイル/リンク時に修正されます。リンカー コマンドによっては、他の関数と同じようにフラッシュに保存される可能性があります。

class I {
  public:
  virtual void doit() = 0;
  virtual void undoit() = 0;
};

class A : public I {
  public:
  virtual void doit () {
    // The code for this function is created statically and stored in the code segment
    std::cout << "hello, ";
  }
  virtual void undoit () {
    // ditto for this one
    std::cout << "HELLO, ";
  }
};

class B : public I {
  public:
  int i;
  virtual void doit() {
    // ditto for this one
    std::cout << "world\n";
  }
  virtual void undoit() {
    // yes, you got it.
    std::cout << "WORLD\n";
  }
};

int main () {
   B b; // So, what is stored inside b?
        // There are sizeof(int) bytes for "i",
        // There are probably sizeof(void*) bytes for the vtable pointer.
        // Note that the vtable pointer doesn't change size, regardless of how
        // many virtual methods there are.
        // sizeof(b) is probably 8 bytes or so.
}
于 2012-06-26T21:49:52.753 に答える
4

メモリ管理の目的で (これは RAM が制限された組み込みシステムです)、オーバーライド関数を静的に割り当てる必要があります。

C++ のすべての関数は、常に静的に割り当てられます。唯一の例外は、JIT を手動でダウンロードして利用する場合です。

于 2012-06-26T22:04:14.043 に答える
2

静的メンバー関数は、クラスの名前空間内にある単なる単純な関数(非メンバー関数など)です。つまり、それらを単純な関数のように扱うことができ、次の解決策で実行する必要があります。

class Interface
{
  public:
    void (*function) ();
};

class Implementation: public Interface
{
  public:
    Implementation()
    {
      function = impl_function;
    }

  private:
    static void impl_function() 
    {
      // do something
    }
};

それから

Implementation a;
Interface* b = &a;
b->function(); // will do something...

このアプローチの問題は、仮想メンバー関数を使用するときにコンパイラーが行うこととほぼ同じことを実行することです(必要なコードが少なく、エラーが発生しにくく、実装関数へのポインターが共有されます)。主な違いはvirtual、関数を使用すると、呼び出されたときに(非表示の)パラメーターを受け取りthis、メンバー変数にアクセスできることです。

したがって、これを行わず、通常の仮想メソッドを使用することをお勧めします。

于 2012-06-26T21:53:44.870 に答える
0

仮想関数のオーバーヘッドは 2 つあります。実際の実装のコード (記述した他の関数と同様に、コード セグメントに存在します) に加えて、仮想関数テーブルがあり、そのテーブルへのポインターがあります。仮想関数テーブルは派生クラスごとに 1 つずつ存在し、そのサイズは仮想関数の数によって異なります。すべてのオブジェクトは、その仮想関数テーブルへのポインターを保持する必要があります。

つまり、仮想関数のオブジェクトごとのオーバーヘッドは、仮想関数の数や含まれるコードの量に関係なく同じです。したがって、ある程度のポリモーフィズムが必要であると判断した場合、仮想関数を配置する方法は、メモリ消費にほとんど影響を与えません。

于 2012-06-26T22:06:09.213 に答える