Как автоматизировать вызов статической перегруженной функции базововго класса?
При перегрузки статичексой функции нужно вызвать перегружаемую статическую функцию базового класса.
Вызовы вручнуную приводят к ошибкам, которые сложно отловить.
Есть ли возможность автоматизировать процесс ???
#include <string>
#include <iostream>
using namespace std;
class A
{
public:
static void create(string& str)
{
str += "A";
}
};
class B : public A
{
// нет перегрузки, используем класса A
};
class C : public B
{
public:
static void create(string& str)
{
B::create(str);
str += "C";
}
};
class D : public C
{
public:
static void create(string& str)
{
C::create(str);
str += "D";
}
};
class E : public B
{
public:
static void create(string& str)
{
C::create(str); // вот закралась ошибка, нужно B::create(str)
str += "E";
}
};
int main(int argc, char *argv[], char *env[])
{
string str;
A::create(str);
cout << str << endl;
str.clear();
B::create(str);
cout << str << endl;
str.clear();
C::create(str);
cout << str << endl;
str.clear();
D::create(str);
cout << str << endl;
str.clear();
E::create(str);
cout << str << endl;
str.clear();
return 0;
};
результат выполнения(из-за copy-paste в E:create, ошибочно вызвали метод другого класса)
A
A
AC
ACD
ACE
требуемый результат выполнения
A
A
AC
ACD
AE
хотелось бы избавиться от необходимости явного указания вызова функции базового класса, чтобы это делал компилятор
как-то так
#include <string>
#include <iostream>
using namespace std;
class A
{
public:
static void create(string& str)
{
str += "A";
}
};
class B : public A
{
// нет перегрузки, используем класса A
};
class C : public B
{
public:
static void create(string& str)
{
str += "C";
}
};
class D : public C
{
public:
static void create(string& str)
{
str += "D";
}
};
class E : public B
{
public:
static void create(string& str)
{
str += "E";
}
};
int main(int argc, char *argv[], char *env[])
{
string str;
A::create(str);
cout << str << endl;
str.clear();
B::create(str);
cout << str << endl;
str.clear();
C::create(str);
cout << str << endl;
str.clear();
D::create(str);
cout << str << endl;
str.clear();
E::create(str);
cout << str << endl;
str.clear();
return 0;
};
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP> Доброго времени суток, Уважаемые.
AP>Как автоматизировать вызов статической перегруженной функции базововго класса? AP>При перегрузки статичексой функции нужно вызвать перегружаемую статическую функцию базового класса. AP>Вызовы вручнуную приводят к ошибкам, которые сложно отловить. AP>Есть ли возможность автоматизировать процесс ???
AP>[ccode] AP>#include <string> AP>#include <iostream>
AP>using namespace std;
AP>class A AP>{ AP>public: AP> static void create(string& str) AP> { AP> str += "A"; AP> } AP>};
AP>class B : public A AP>{ AP>// нет перегрузки, используем класса A AP>};
AP>class C : public B AP>{ AP>public: AP> static void create(string& str) AP> { AP> B::create(str); AP> str += "C"; AP> } AP>};
AP>class D : public C AP>{ AP>public: AP> static void create(string& str) AP> { AP> C::create(str); AP> str += "D"; AP> } AP>};
AP>class E : public B AP>{ AP>public: AP> static void create(string& str) AP> { AP> C::create(str); // вот закралась ошибка, нужно B::create(str) AP> str += "E"; AP> } AP>};
Маленькая поправочка: в данном случае имеет место не перегрузка функций, а сокрытие — C::create скрывает A::create, D::create скрывает C::create и т.д.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: Цепочка вызовов перегруженных статических функций
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP>хотелось бы избавиться от необходимости явного указания вызова функции базового класса, чтобы это делал компилятор AP>как-то так
...
ИМХО так делать точно не стоит — наличие скрытого функционала никак не способствует улучшению читабельности кода.
Можно попробовать что-то типа вот этого:
template <class T>
class parent_t : public T
{
protected:
typedef T Base;
};
class A
{
public:
static void create(string& str)
{
str += "A";
}
};
class B : publicparent_t<A>
{
// нет перегрузки, используем класса A
};
class C : publicparent_t<B>
{
public:
static void create(string& str)
{
Base::create(str);
str += "C";
}
};
ИМХО это несколько снижает вероятность ошибок.
Можно вместо шаьлона parent_t использовать платформенно-зависимые фичи, например __super в MSVC
class C : publicparent_t<B>
{
public:
static void create(string& str)
{
__super::create(str);
str += "C";
}
};
Любите книгу — источник знаний (с) М.Горький
Re[2]: Цепочка вызовов перегруженных статических функций
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP>Интересно, спасибо. AP>Можно как-то совсем избавиться от необходимости явного вызова перекрытой функции?
Ну вот первое, что приходит в голову:
template <class D, class B>
class parent_t : public B
{
public:
static void create(string& str)
{
B::create_impl(str);
D::create_impl(str);
}
};
class A
{
public:
static void create(string& str) { create_impl(str); }
static void create_impl(string& str)
{
str += "A";
}
};
class B : public A
{
// нет перегрузки, используем класса A
};
class C : public parent_t<C, B>
{
public:
static void create_impl(string& str)
{
str += "C";
}
};
Но мне это решение не нравится.
Любите книгу — источник знаний (с) М.Горький
Re[2]: Цепочка вызовов перегруженных статических функций
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP>Как автоматизировать вызов статической перегруженной функции базововго класса? AP>При перегрузки статичексой функции нужно вызвать перегружаемую статическую функцию базового класса. AP>Вызовы вручнуную приводят к ошибкам, которые сложно отловить. AP>Есть ли возможность автоматизировать процесс ???
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP>Можно как-то совсем избавиться от необходимости явного вызова перекрытой функции?
Зависит от того, что из себя представляют классы.
Если они служат лишь для конструирования строки, то можно заменить на mpl-списки, например.
Если же это "просто классы", в которые ты хочешь добавить фичу...
Ну например, такое. Поскольку ты хочешь, чтобы реализация (create_impl) не парилась об организации забега по иерархии — вынеси этот забег наружу.
// официальный механизм наследованияstruct root
{
static void create_impl(string&) {}
};
template<class S> struct derive : S { typedef S superclass; };
// забег по классуtemplate<class T> struct runner
{
static void create(string& s)
{
typedef typename T::superclass S;
runner<S>::create(s);
if( &T::create_impl != &S::create_impl ) T::create_impl(s); // можно вынести во время компиляции
}
};
template<> struct runner<root>
{
static void create(string&) {}
};
class A : public root { ..... };
class B : public derive<A> { ..... };
class C : public derive<B> { ..... };
int main()
{
string s;
runner<C>::create(s); // вместо C::create(s);
}
Либо по-простецки, на макросах — просто избавь себя от копипаста
#define DECLARE_CREATE_IMPL(s) \
static void create(string& s) { __super::create(s); create_impl(s); } /* здесь мы определяем порядок обхода */ \
static void create_impl(string& s) /* а здесь сразу же объявляем перегрузку - чтобы уже не отвертеться */ \
//endmacro#define DEFINE_CREATE_IMPL(T,s) void T::create_impl(string& s) /* для реализации вне объявления класса */struct root { static void create(string&) {} };
struct A : root
{
DECLARE_CREATE_IMPL(boo) // можем давать любые имена параметру
// далее следует инлайновое определение create_impl(string& boo)
{
boo += "A";
}
};
struct B : A
{
DECLARE_CREATE_IMPL(x);
};
inline DEFINE_CREATE_IMPL(B,x) { x += "B"; }
struct C : B
{};
struct D : C
{
DECLARE_CREATE_IMPL(s);
};
// где-то в .cpp
DEFINE_CREATE_IMPL(D,q) { q += "D"; }
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[2]: Цепочка вызовов перегруженных статических функций
Здравствуйте, Кодт, Вы писали:
К>Зависит от того, что из себя представляют классы.
Private переменные-параметры.
Т.е. представляют из себя иерархию свойств.
class BaseData {
int modAddr; //адрес устройства
};
class Mod1Data : public BaseData {
time_t lastEvent; // время последнего события
};
class Mod2Data : public BaseData {
time_t onLen; // продолжительность включения
};
Здравствуйте, Alexander Pazdnikov, Вы писали:
AP>Здравствуйте, Кодт, Вы писали:
AP>как обойти
Было
class A : public root
{
A(int modNum, const string& modType) {};
};
class B : public derive<A>
{
B(int modNum, const string& modType) : A(modNum, modType) {};
}
Стало
template <class S> struct derive
{
derive(int modNum, const std::string& modType) : S(modNum, modType) {};typedef S superclass;
};
class A : public root
{
A(int modNum, const std::string& modType) {};
};
class B : public derive<A>
{
B(int modNum, const std::string& modType) : derive<A>(modNum, modType) {};
}
Изменения неизбежны ?
Re[6]: Цепочка вызовов перегруженных статических функций