19

私はクラスを持っています。それをAと呼びましょう。そのクラス定義内には次のものがあります。

static QPainterPath *path;

つまり、パス オブジェクトへの静的な (クラス全体の) ポインターを宣言しています。このクラスのすべてのインスタンスは、同じ共有データ メンバーを持つようになります。このクラスに基づいて構築し、より特殊な形式にサブクラス化し、動作を階層化し、各クラスが独自のパス オブジェクトを持ちます (ただし、バウンディング ボックスの計算やペイント ルーチンの呼び出しなどの退屈なビットを繰り返す必要はありません)。 )。

クラスFを作成するためにサブクラス化する場合(たとえば)、FでAから継承された描画ルーチンを使用する必要がありますが、Fで宣言された静的(クラス全体)のパスオブジェクトを使用します。上記の宣言をプライベート セクション (および派生クラス F でそれを繰り返します) を保護セクションに配置しようとしましたが、すべて喜びがありませんでした。

なぜこれが起こっているのか、私はある程度見ることができます:

void A::paint() {
    this->path...

オブジェクトがクラス F であっても、F::path ではなく A::path を参照しています。

これを回避し、基本クラスで定義された描画コードを引き続き使用し、すべてのクラス (おそらく基本クラスを除く) を実際にインスタンス化できるようにしながら、各クラスが静的パス オブジェクトを維持できるようにするエレガントな方法はありますか?

4

8 に答える 8

10

You might be able to do a variant on a mix in or Curiously recurring template pattern

#include <stdio.h>

typedef const char QPainterPath;

class Base
{
public:
    virtual void paint() { printf( "test: %s\n", getPath() ); }
    virtual QPainterPath* getPath() = 0;
};

template <class TYPE>
class Holder : public Base
{
protected:
    static QPainterPath* path;
    virtual QPainterPath* getPath() { return path; }
};

class Data1 : public Holder<Data1>
{
};

class Data2 : public Holder<Data2>
{
};

template <> QPainterPath* Holder<Data1>::path = "Data1";
template <> QPainterPath* Holder<Data2>::path = "Data2";

int main( int argc, char* argv[] )
{
Base* data = new Data1;
data->paint();
delete data;

data = new Data2;
data->paint();
delete data;
}

I have just run this code in CodeBlocks and got the following:

test: Data1
test: Data2

Process returned 0 (0x0)   execution time : 0.029 s
Press any key to continue.
于 2009-02-27T13:55:39.770 に答える
8

私はこれをテストしていませんが、仮想関数を導入しています:

struct Base {

    void paint() {
         APath * p = getPath();
         // do something with p
    }

    virtual APath * getPath() {
         return myPath;
    }

    static APath * myPath;
};

struct Derived : public Base  {

    APath * getPath() {
         return myPath;
    }
    static APath * myPath;
};

あなたが望むものかもしれません。2 つの statics をどこかに定義する必要があることに注意してください。

APath * Base::myPath = 0;
APath * Derived::myPath = 0;
于 2009-02-27T13:38:24.073 に答える
2

この質問には回答済みですが、ヘルパー クラスとテンプレートの特殊化を使用して、複数のクラスに同様の静的変数の値を設定する別の方法があります。

サブクラス化とはまったく関係がないため、質問に正確に答えることはできませんが、同じ問題に遭遇し、共有したい別の解決策を見つけました。

例 :

template <typename T>
struct Helper {
  static QPainterPath* path;
  static void routine();
}

// Define default values
template <typename T> QPainterPath* Helper<T>::path = some_default_value;
template <typename T> void Helper<T>::routine { do_somehing(); }

class Derived {};

// Define specialized values for Derived
QPainterPath* Helper<Dervied>::path = some_other_value;
void Helper<Dervied>::routine { do_somehing_else(); }

int main(int argc, char** argv) {
  QPainterPath* path = Helper<Derived>::path;
  Helper<Derived>::routine();
  return 0;
}

長所:

  • クリーン、コンパイル時の初期化
  • 静的アクセス (インスタンス化なし)
  • 特殊な静的関数も宣言できます

短所:

  • 仮想化がないため、情報を取得するには正確なタイプが必要です
于 2016-07-12T12:47:09.773 に答える
0

外観を気にしない場合は、パスを使用する前に A:: または F:: を使用して正しいものを選択するか、:: が気に入らない場合は別の名前を付けます。

別のオプションは、関数を使用してこれを整理することです。たとえば、 virtual QPainterPath* GetPath() { return A::path; } A および QPainterPath* の GetPath() { return F::path; } で F.

実際には、この問題はコードが何をするかではなく、コードがどのように見えるかに関するものであり、可読性を実際に変えるものではないので、これについて心配することはありません...

于 2009-02-27T13:38:58.937 に答える
0

静的メンバー変数はもちろん、静的関数を「オーバーライド」することはできません。

必要なのは、おそらく仮想関数です。これらはインスタンス関数にしかできないため、クラス インスタンスなしではアクセスできません。

于 2009-02-27T13:33:17.517 に答える
0

おそらく、静的変数をオーバーライドしたくないでしょう。代わりに、クラスにポインタを格納できますか?

class A
{
    public:
        A() :
            path(static_path)
        {
        }

    protected:
        A(QPainterPath *path)
            : path(path)
        {
        }

    private:
        QPainterPath *path;

        static QPainterPath *static_path;  /* Lazy initalization? */
};

class F : public A
{
    public:
        F() :
            A(F_static_path)
        {
        }

    private:
        static QPainterPath *F_static_path;  /* Lazy initalization? */
};
于 2009-02-27T13:35:16.217 に答える