Переопределение статических переменных при создании подклассов - PullRequest
16 голосов
/ 27 февраля 2009

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

static QPainterPath *path;

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

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

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

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

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

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

Ответы [ 8 ]

16 голосов
/ 27 февраля 2009

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

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() ...
}
10 голосов
/ 27 февраля 2009

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

#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.
7 голосов
/ 27 февраля 2009

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

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;
2 голосов
/ 27 февраля 2009

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

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;
}
1 голос
/ 12 июля 2016

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

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

Пример:

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

Плюсы:

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

Минусы:

  • нет виртуализации, вам нужен точный тип для получения информации
0 голосов
/ 27 февраля 2009

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

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

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

0 голосов
/ 27 февраля 2009

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

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? */
};
0 голосов
/ 27 февраля 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...