Переопределение статических переменных при подклассификации

У меня есть класс, давайте назовем его A, и внутри этого определения класса у меня есть следующее:

static QPainterPath *path;

Иными словами, я объявляю статический (общеуровневый) указатель на объект пути; все экземпляры этого класса теперь будут иметь один и тот же общий элемент данных. Я хотел бы иметь возможность использовать этот класс, подклассифицируя его в более специализированные формы, поведение слоев и каждый класс имеет свой собственный уникальный объект пути (но не должен повторять сверлящие биты, такие как вычисление ограничивающих прямоугольников или вызов подпрограмм рисования).

Если я подклассифицирую его для создания класса F (например), я хочу, чтобы F использовал унаследованные процедуры рисования из A, но для использования статического (общедоступного) объекта пути, объявленного в F. Я попытался иметь объявление в частном разделе (и повторение его в производном классе F), и попробовал его в защищенном разделе, без радости.

Я могу понять, почему это происходит:

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

ссылается на A:: path вместо F:: path, даже если объект имеет класс F.

Есть ли элегантный способ обойти это и позволить каждому классу поддерживать статический объект пути, сохраняя при этом код чертежа, определенный в базовом классе, и иметь все классы (кроме, возможно, базового класса), быть реальными и инстантабельными

Ответы

Ответ 1

Используйте виртуальный метод для получения ссылки на статическую переменную.

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() ...
}

Ответ 2

Возможно, вы сможете сделать вариант в миксе или Любопытно повторяющийся шаблон шаблона

#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.

Ответ 3

Я не тестировал это, но ввел виртуальную функцию:

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;

Ответ 4

Вы можете использовать виртуальные функции для достижения своего результата. Это, вероятно, ваше самое чистое решение.

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

Ответ 5

Вы не можете "переопределять" статические функции, не говоря уже о статических переменных-членах.

Вам нужна виртуальная функция. Это могут быть только функции экземпляра, поэтому они не будут доступны без экземпляра класса.

Ответ 6

Вероятно, вы не хотите, чтобы статические переменные перегружались. Может быть, вы можете сохранить указатель в своем классе?

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

Если вы не заботитесь о внешнем виде, просто используйте A:: или F:: перед использованием пути, чтобы выбрать правильный, или если вам не нравится:: назовите их по-разному.

Другой вариант - использовать функцию, чтобы убрать ее, например. виртуальный QPainterPath * GetPath() {return A:: path; } в и QPainterPath * GetPath() {return F:: path; } в F.

Действительно, хотя эта проблема касается только того, как выглядит код, а не того, что он делает, и поскольку он не меняет читаемости, я бы не беспокоился об этом...

Ответ 8

Я знаю, что на этот вопрос был дан ответ, но есть другой способ установить значение аналогичной статической переменной для нескольких классов через вспомогательный класс и некоторую специализированную специализацию.

Он точно не отвечает на вопрос, так как он никак не связан с подклассом, но я столкнулся с одной и той же проблемой, и я нашел другое решение, которое хотел разделить.

Пример:

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

Плюсы:

  • чистая, инициализация времени компиляции
  • статический доступ (без экземпляра)
  • вы также можете объявить специализированные статические функции

Минусы:

  • нет виртуализации, вам нужен точный тип для извлечения информации