子类化时覆盖静态变量

时间:2009-02-27 13:28:32

标签: c++ inheritance static override

我有一个类,我们称之为A,在该类定义中我有以下内容:

static QPainterPath *path;

也就是说,我正在声明一个指向路径对象的静态(类范围)指针;此类的所有实例现在都具有相同的共享数据成员。我希望能够构建这个类,将其子类化为更专业的形式,分层行为,并且每个类都有自己唯一的路径对象(但不必重复无聊的位,如计算边界框或调用绘制例程)。

如果我将它子类化为创建类F(例如),我希望F使用A中继承的绘图例程,但是要使用在F中声明的静态(类范围)路径对象。我尝试过在私有部分上面的声明(并在派生类F中重复它),并尝试在受保护的部分中使用它,一切都没有乐趣。

我可以理解为什么会发生这种情况:

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

指的是A :: path而不是F :: path,即使对象属于F类。

是否有一种优雅的方法来绕过这个,并允许每个类维护一个静态路径对象,同时仍然使用基类中定义的绘图代码,并使所有类(除了基类)都是真实的和可实例化的?

8 个答案:

答案 0 :(得分:16)

使用虚方法获取对静态变量的引用。

class Base {
private:
    static A *a;
public:
    A* GetA() {
        return a;
    }
};

class Derived: public Base {
private:
    static B *b;
public:
    A* GetA() {
        return b;
    }
};

请注意,B来自A。然后:

void Derived::paint() {
    this->GetA() ...
}

答案 1 :(得分:10)

您或许可以在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;
}

我刚刚在CodeBlocks中运行此代码并获得以下内容:

test: Data1
test: Data2

Process returned 0 (0x0)   execution time : 0.029 s
Press any key to continue.

答案 2 :(得分:7)

我没有对此进行测试,但引入了虚函数:

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;
};

可能是你想要的。请注意,您仍需要在某处定义两个静态:

APath * Base::myPath = 0;
APath * Derived::myPath = 0;

答案 3 :(得分:2)

您可以使用虚拟功能来实现结果。这可能是您最干净的解决方案。

class A
{
    protected:
        virtual QPainterPath *path() = 0;

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

QPainterPath *A::path()
{
    return A::static_path;
}

class F : public A
{
    protected:
        virtual QPainterPath *path() = 0;

    private:
        static QPainterPath *F_static_path;  /* Lazy initalization? */
};

QPainterPath *A::path()
{
    return F::F_static_path;
}

答案 4 :(得分:1)

我知道这个问题已得到解答,但还有另一种方法可以通过辅助类和一些模板专门化为多个类设置类似静态变量的值。

它没有完全回答这个问题,因为它没有以任何方式与子类连接,但我遇到了同样的问题,我发现了一个我想分享的不同解决方案。

示例:

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;
}

优点:

  • 清理,编译时初始化
  • 静态访问(无实例化)
  • 您也可以声明专门的静态函数

缺点:

  • 没有虚拟化,您需要确切的类型来检索信息

答案 5 :(得分:0)

你不能“覆盖”静态函数,更不用说静态成员变量了。

您需要的可能是虚拟功能。这些只能是实例函数,因此没有类实例就无法访问它们。

答案 6 :(得分: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? */
};

答案 7 :(得分:0)

如果您不关心外观,只需使用A ::或F ::在使用路径之前选择正确的,或者如果您不喜欢::以不同方式命名它们。

另一个选择是使用一个函数来整理它,例如virtual QPainterPath * GetPath(){return A :: path;在A和QPainterPath * GetPath(){return F :: path;在F。

实际上这个问题只是关于代码的外观而不是它的作用,因为它并没有真正改变可读性,所以我不会为此烦恼...