首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QSharedData和继承

QSharedData和继承
EN

Stack Overflow用户
提问于 2012-09-25 16:34:37
回答 4查看 2.3K关注 0票数 5

我试图在使用QSharedData的同时创建一个类型系统。想法很简单,将有许多不同的数据类型,每种类型都将从基础抽象类派生。我想使用QSharedData来存储每个派生类中的实际数据,但是每个派生类都将有不同的数据存储在其中。我现在正在试着做一个最基本的例子,但是遇到了一些麻烦。

假设这些是我的基础纯虚拟类:

代码语言:javascript
复制
class cAbstractData: public QSharedData
{
public:
    cAbstractData(){ }
    virtual int type() = 0;
};

class cAbstractValue
{
public:
    cAbstractValue(){ }
    virtual int type() = 0;
protected:
    QSharedDataPointer<cAbstractData>data_;
};

现在,假设我想创建一个类来表示单个值(这是一个最小的例子)。我从基值类派生了cAtomicValue,还派生了一个数据类来保存该值:

代码语言:javascript
复制
class cAtomicData:public cAbstractData
{
public:
    cAtomicData() { value_ = 0; }
    int type(){ return 1; }
    QVariant value_;//the actual value
};

class cAtomicValue:public cAbstractValue
{
public:
    cAtomicValue() { 
        data_ = new cAtomicData;//creating the data object.
    }
    int type(){ return 1; }
};

现在在这个阶段,它工作得很好,并且在调试器中我可以看到正确的指针类型。但是现在我想添加一个用于设置和获取值的函数,但我不知道该如何做。让我们以setter为例。要设置该值,我们必须通过cAtomicData类的data_成员访问cAtomicValue类的cAtomicValue成员。但是,由于data_包含基类指针(cAbstractData),因此我必须以某种方式将其转换为正确的类型(cAtomicData)。我试过这样做:

代码语言:javascript
复制
template<class T> void set( T value )
{
    static_cast<cAtomicData*>(data_.data())->value_ = value;
}

它显然不起作用,因为它调用了detach()并试图复制基类,但由于基类是纯虚拟的,所以它无法做到这一点。然后,我尝试强制转换指针本身:

代码语言:javascript
复制
static_cast<cAtomicData*>(data_)->value_ = value;

但是我得到了一个invalid static_cast ...错误。

我该怎么做,我是否从根本上正确地做了这件事?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-09-25 20:23:26

我看不出有什么办法能达到你想要的效果。正如您已经发现的,QSharedDataPointer需要在它包含的实际类型上模板化。

你可以让你的基类成为一个模板,例如

代码语言:javascript
复制
template<class T>
class cAbstractValue
{
public:
    cAbstractValue(){ }
    virtual int type() = 0;
protected:
    QSharedDataPointer<T> data_;
};

但我不确定我能从中得到什么好处。

票数 2
EN

Stack Overflow用户

发布于 2012-10-03 17:14:22

您可以切换到QExplicitlySharedDataPointer而不是QSharedDataPointer。这样,当您试图获取指向cAbstractData对象的非常数指针时,就不会调用detach(),这包括将QExplicitlySharedDataPointer<cAbstractData>对象强制转换为QExplicitlySharedDataPointer<cAtomicData>对象。但是,如果要使用写入时复制,则每次要修改cAbstractData时都需要手动调用detach()。也许你可以编写一个包装器类来为你执行分离。

这种方法可能比使用QSharedPointer更可取,因为QExplicitlySharedDataPointer的大小与普通指针相同(因此保持了二进制兼容性),而QSharedPointer的大小是普通指针的两倍(参见this blog entry)。

编辑:请注意,从QExplicitlySharedDataPointer<cAbstractData>QExplicitlySharedDataPointer<cAtomicData>的强制转换是静态的,因此您必须保证实际引用的对象是cAtomicData类型(或子类的对象),否则使用指针时的行为可能是未定义的。

票数 6
EN

Stack Overflow用户

发布于 2014-09-21 18:56:29

我在我的应用程序中遇到了类似的问题,下面是我如何解决它的。我有一个使用Pimpl惯用法和指向BaseClassPrivateQExplicitlySharedDataPointer实现的BaseClass。此类由DerivedClass继承,其私有成员是继承BaseClassPrivateDerivedClassPrivate

BaseClassPrivate有一个名为baseParam的float成员,DerivedClassPrivate有另一个名为derivedParam的float参数。

我通过以下方式解决了这个问题:

  1. 定义受保护的构造函数BaseClass(BaseClassPrivate* p)

它用于通过指向BaseClassPrivateDerivedClassPrivate中的虚拟clone()方法的指针来实例化新的派生类

每当需要进行深度复制时,都会调用此方法来正确复制私有类。因此,我们不是调用'QExplicitlySharedDataPointer::detach()',而是检查克隆引用计数器是否大于1,然后调用QSharedData。请注意,QSharedData::ref不在文档中,因此它可以随时更改(即使这似乎不太可能发生soon).

  • Static在DerivedClass中强制转换d指针

我发现定义私有dCasted()函数很方便。

为了测试这一点,在BaseClassPrivateDerivedClassPrivate中引入了虚拟函数foo(),它相应地返回baseParamderivedParam

代码如下:

BaseClass.h

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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);
    }
};

现在,我们可以做如下事情:

调用虚函数:

代码语言:javascript
复制
DerivedClass derived;
derived.setDerivedParam(1.0);
QCOMPARE(derived.foo(), 1.0);   // proving that DerivedClassPrivate::foo() is called

正确地从DerivedClass复制到BaseClass

代码语言:javascript
复制
BaseClass baseCopy = derived;   
QCOMPARE(baseCopy.foo(), 1.0);   // proving that DerivedClassPrivate::foo() is called  
                                 // even after copying to a BaseClass

根据原始类从BaseClass复制到BaseClass,并正确地进行写入时复制:

代码语言:javascript
复制
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

希望这能有所帮助

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12579091

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档