私は自分のアプリケーションで同様の問題を抱えていました。これが私がそれを解決した方法です。BaseClass
Pimplイディオムを使用して実装されているQExplicitlySharedDataPointer
を持っていBaseClassPrivate
ます。このクラスは、DerivedClass
そのプライベートメンバーがDerivedClassPrivate
継承であるによって継承されBaseClassPrivate
ます。
BaseClassPrivate
1つのfloatメンバーという名前がbaseParam
あり、DerivedClassPrivate
別のfloatパラメーターという名前がありderivedParam
ます。
私は次のようにしてこの問題を解決しました:
保護されたコンストラクターを定義するBaseClass(BaseClassPrivate* p)
これは、へのポインタを使用して新しい派生クラスをインスタンス化するために使用されますDerivedClassPrivate
との両方で仮想clone()
メソッドを定義するBaseClassPrivate
DerivedClassPrivate
このメソッドは、ディープコピーが必要な場合にプライベートクラスを正しくコピーするために呼び出されます。したがって、「QExplicitlySharedDataPointer :: detach()」を呼び出す代わりに、QSharedData参照カウンターが1より大きいかどうかを確認してから、cloneを呼び出します。QSharedData :: refはドキュメントに含まれていないため、いつでも変更される可能性があることに注意してください(すぐに発生する可能性は低いようですが)。
dポインタを静的にキャストしますDerivedClass
プライベートdCasted()
関数を定義すると便利だと思います。
これをテストするために、仮想関数がとにfoo()
導入されます。これは、またはそれに応じて戻ります。BaseClassPrivate
DerivedClassPrivate
baseParam
derivedParam
コードは次のとおりです。
BaseClass.h
class BaseClass
{
public:
BaseClass() : d(new BaseClassPrivate()) {}
BaseClass(const BaseClass& other) : d(other.d) {}
BaseClass& operator =(const BaseClass& other) {d = other.d; return *this;}
virtual ~BaseClass() {}
float baseParam() const {return d->baseParam;}
void setBaseParam(float value) {
detach(); // instead of calling d.detach()
d->baseParam = value;
}
float foo() const {return d->foo();}
protected:
BaseClass(BaseClassPrivate* p) : d(p) {}
void detach() {
// if there's only one reference to d, no need to clone.
if (!d || d->ref == 1) return; // WARNING : d->ref is not in the official Qt documentation !!!
d = d->clone();
}
QExplicitlySharedDataPointer<BaseClassPrivate> d;
};
DerivedClass.h
class DerivedClass : public BaseClass
{
public:
DerivedClass() : BaseClass(new DerivedClassPrivate()) {}
float derivedParam() const {return dCasted()->derivedParam;}
void setDerivedParam(float value) {
detach(); // instead of calling d.detach();
dCasted()->derivedParam = value;
}
private:
DerivedClassPrivate* dCasted() const {return static_cast<DerivedDataPrivate*>(d.data());}
};
BaseClassPrivate.h
class BaseClassPrivate : public QSharedData
{
public:
BaseClassPrivate() : QSharedData(), baseParam(0.0) {}
BaseClassPrivate(const BaseClassPrivate& other) :
QSharedData(other), baseParam(other.baseParam) {}
virtual ~BaseClassPrivate() {}
float baseParam;
virtual float foo() const {return baseParam;}
virtual BaseClassPrivate* clone() const {
return new BaseClassPrivate(*this);
}
};
DerivedClassPrivate.h
class DerivedClassPrivate : public BaseClassPrivate
{
public:
DerivedClassPrivate() : BaseClassPrivate(), derivedParam(0.0) {}
DerivedClassPrivate(const DerivedClassPrivate& other) :
BaseClassPrivate(other), derivedParam(other.derivedParam) {}
float derivedParam;
virtual float foo() const {return derivedParam;}
virtual BaseClassPrivate* clone() const {
return new DerivedClassPrivate(*this);
}
};
今、私たちは次のようなことをすることができます:
仮想関数を呼び出す:
DerivedClass derived;
derived.setDerivedParam(1.0);
QCOMPARE(derived.foo(), 1.0); // proving that DerivedClassPrivate::foo() is called
DerivedClass
からにBaseClass
正しくコピーを作成します。
BaseClass baseCopy = derived;
QCOMPARE(baseCopy.foo(), 1.0); // proving that DerivedClassPrivate::foo() is called
// even after copying to a BaseClass
からコピーを作成し、元のクラスBaseClass
をBaseClass
尊重し、コピーオンライトを正しく作成します。
BaseClass bbCopy(baseCopy); // make a second copy to another BaseClass
QCOMPARE(bbCopy.foo(), 1.0); // still calling DerivedClassPrivate::foo()
// copy-on-write
baseCopy.setBaseParam(2.0); // this calls the virtual DerivedClassPrivate::clone()
// even when called from a BaseClass
QCOMPARE(baseCopy.baseParam(), 2.0); // verify the value is entered correctly
QCOMPARE(bbCopy.baseParam(), 1.0); // detach is performed correctly, bbCopy is
// unchanged
QCOMPARE(baseCopy.foo(), 1.0); // baseCopy is still a DerivedClass even after detaching
お役に立てれば