Переопределение статических переменных при подклассификации
У меня есть класс, давайте назовем его 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;
}
Плюсы:
- чистая, инициализация времени компиляции
- статический доступ (без экземпляра)
- вы также можете объявить специализированные статические функции
Минусы:
- нет виртуализации, вам нужен точный тип для извлечения информации