19

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

static QPainterPath *path;

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

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

我可以看到为什么会这样:

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

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

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

4

8 回答 8

20

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

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() ...
}
于 2009-02-27T13:36:14.343 回答
10

您也许可以在混合或奇怪重复的模板模式上做一个变体

#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.
于 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;
};

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

APath * Base::myPath = 0;
APath * Derived::myPath = 0;
于 2009-02-27T13:38:24.073 回答
3

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

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;
}
于 2009-02-27T13:36:58.710 回答
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

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

你需要的可能是一个虚函数。这些只能是实例函数,因此如果没有类实例,它们将无法访问。

于 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 回答
0

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

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

真的,虽然这个问题只是关于代码的外观而不是它的作用,而且由于它并没有真正改变可读性,我不会为此担心......

于 2009-02-27T13:38:58.937 回答