我在我的应用程序中遇到了类似的问题,这就是我解决它的方法。我有一个BaseClass
使用 Pimpl 成语实现并QExplicitlySharedDataPointer
指向BaseClassPrivate
. 此类DerivedClass
由其私有成员继承的DerivedClassPrivate
继承BaseClassPrivate
。
BaseClassPrivate
有一个名为的浮点成员baseParam
和DerivedClassPrivate
另一个名为的浮点参数derivedParam
。
我通过以下方式解决了这个问题:
定义受保护的构造函数BaseClass(BaseClassPrivate* p)
这用于使用指向的指针实例化新的派生类DerivedClassPrivate
在和中定义一个虚clone()
方法BaseClassPrivate
DerivedClassPrivate
每当需要深度复制时,都会调用此方法来正确复制私有类。因此,我们不调用“QExplicitlySharedDataPointer::detach()”,而是检查 QSharedData 引用计数器是否大于 1,然后调用 clone。请注意 QSharedData::ref 不在文档中,因此它可以随时更改(即使它似乎不太可能很快发生)。
静态转换 d 指针DerivedClass
dCasted()
我发现定义一个私有函数很方便。
为了测试这一点,在andfoo()
中引入了虚函数,它返回或相应地返回。BaseClassPrivate
DerivedClassPrivate
baseParam
derivedParam
这是代码:
基类.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;
};
派生类.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
希望这可以帮助