Существует ли шаблон проектирования в любом основном языке для производного класса, чтобы наследовать код от базового класса и оценить этот код в области видимости производного класса? Например (с использованием синтаксиса псевдо-C ++):
class Base {
// (How) can this be modified to be evaluated
// in the derived class's scope so that it
// prints the size of the derived class?
void printSize() {
cout << sizeof(*this) << endl;
}
};
class Derived : public Base {
void* dummy;
};
int main() {
Base base;
Derived derived;
base.printSize();
derived.printSize(); // Should be > base.printSize().
return 0;
}
Я понимаю, что это можно сделать с помощью макросов, но для этого требуется явная реализация макроса в области видимости производного класса.
РЕДАКТИРОВАТЬ: Чтобы уточнить, весь смысл этого поста в том, что я не хочу, чтобы вручную повторно реализовать printSize()
или что-нибудь подобное в каждом производном классе. Я ищу умный шаблон, чтобы компилятор / интерпретатор (мне интересно знать, есть ли у какого-нибудь языка решение для этого, даже если я использовал C ++ в моем примере), сделал это для меня.
РЕДАКТИРОВАТЬ № 2: Я думаю, что это довольно просто в динамических языках. Меня больше интересуют решения для статически типизированных языков, в основном C ++, Java и D.
РЕДАКТИРОВАТЬ № 3: Шаблон должен работать с типом времени выполнения, а не типом времени компиляции. Поэтому в шаблоне D эти параметры не являются решением.
Если под «основной» вы включите основные скриптовые языки, такие как Perl или Python, то да. Методы Perl обычно «оцениваются» в самой производной области, поскольку «объект» Perl обычно представляет собой хэш-карту, и все переменные всех уровней дерева наследования находятся в одной и той же «области видимости» (то есть ключи в та же хэш-карта). Нечто подобное происходит и с классами Python, хотя (IIRC) в Python есть способ создания символа, который будет искажен, чтобы он отличался в зависимости от класса, в котором написан код. Конечно, ни один из этих языков не имеет «sizeof» «Концепция сама по себе, так что ваш конкретный пример не будет особенно уместным.
В C ++ концепция определения текущего класса для функции-члена, основанная на типе, через который она вызывается, как ваш пример, не (насколько я знаю) действительно работает. Тем не менее, вы можете быть в состоянии приблизиться к тому, что вы описываете, используя шаблоны. Например, что-то вроде этого:
template<typename T>
void printSize( T &t ) {
cout << sizeof(t) << endl;
}
int main() {
Base base;
Derived derived;
printSize(base);
printSize(derived);
}
(Примечание: в C ++, так как ваш Base
пусто, на самом деле нет никакой гарантии, что sizeof(Base)
> sizeof(Derived)
— можно использовать пустую базовую оптимизацию, чтобы Base
является (возможно) размером указателя, но Base
часть Derived
на самом деле пусто. Большинство платформ, вероятно, выделяют 1 байт таким пустым классам, и указатели обычно больше, чем это, но это не указано.)
D приходит на помощь. Шаблонные миксины это именно тот инструмент, который предназначен для оценки в целевом контексте, и вам не нужна какая-либо специальная иерархия типов (вы можете добавить ее, если хотите, конечно):
http://dpaste.1azy.net/eec411e8
mixin template SizePrinter()
{
static void printSize()
{
import std.stdio;
writeln(__traits(classInstanceSize, typeof(this)));
}
}
class Tested1
{
int[64] dummy;
mixin SizePrinter;
}
class Tested2
{
int[16] dummy;
mixin SizePrinter;
}
void main()
{
Tested1.printSize();
Tested2.printSize();
}
Выход приложения:
272
80
В C ++ я думаю, что чем ближе к этому Любопытно повторяющийся шаблон (CRTP), но имеет серьезные ограничения:
template<typename T>
class Base {
void printSize() {
std::cout << sizeof(T) << std::endl;
}
void doSomething() {
T::member_variable = 3;
T::doSomethingElse();
}
};
class Derived : public Base<Derived> {
public:
int member_variable;
void doSomethingElse() { ... }
};
Вы также можете использовать виртуальные методы, но они требуют от вас переопределить метод в каждом производном классе, так что я думаю, это не то, что вам нужно.
Чтобы действительно достичь того, что вы имеете в виду, вам, вероятно, понадобится динамический язык (например, Python). Хотя никаких гарантий, это такой необычный «запрос функции», и я не очень хорошо знаю динамические языки …
Есть лучшее решение в D, которое использует Шаблон этого параметра.
Код: http://dpaste.1azy.net/78810a79
import std.stdio;
class Base {
int[64] dummy1;
final static size_t getSize(this T)() {
return __traits(classInstanceSize, T);
}
}
class Derived : Base {
int[16] dummy2;
}
void main() {
writeln(Base.getSize()); // prints: 272
writeln(Derived.getSize()); // prints: 336
}
Изменить: Опс, это будет работать только для статического типа. Не решение вашей проблемы.