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

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

static QPainterPath *path; 

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

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

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

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

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

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

8 Solutions collect form web for “Переопределение статических переменных при подclassификации”

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

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

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

 #include  typedef const char QPainterPath; class Base { public: virtual void paint() { printf( "test: %s\n", getPath() ); } virtual QPainterPath* getPath() = 0; }; template  class Holder : public Base { protected: static QPainterPath* path; virtual QPainterPath* getPath() { return path; } }; class Data1 : public Holder { }; class Data2 : public Holder { }; template <> QPainterPath* Holder::path = "Data1"; template <> QPainterPath* Holder::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. 

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

 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; 

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

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

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

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

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

 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? */ }; 

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

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

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

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

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

Пример :

 template  struct Helper { static QPainterPath* path; static void routine(); } // Define default values template  QPainterPath* Helper::path = some_default_value; template  void Helper::routine { do_somehing(); } class Derived {}; // Define specialized values for Derived QPainterPath* Helper::path = some_other_value; void Helper::routine { do_somehing_else(); } int main(int argc, char** argv) { QPainterPath* path = Helper::path; Helper::routine(); return 0; } 

Плюсы:

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

Минусы:

  • нет виртуализации, вам нужен точный тип для извлечения информации
Давайте будем гением компьютера.