Наследование: оценка в производном классе?

Существует ли шаблон проектирования в любом основном языке для производного класса, чтобы наследовать код от базового класса и оценить этот код в области видимости производного класса? Например (с использованием синтаксиса псевдо-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 эти параметры не являются решением.

2

Решение

Если под «основной» вы включите основные скриптовые языки, такие как 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 байт таким пустым классам, и указатели обычно больше, чем это, но это не указано.)

2

Другие решения

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
2

В 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). Хотя никаких гарантий, это такой необычный «запрос функции», и я не очень хорошо знаю динамические языки …

1

Есть лучшее решение в 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
}

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

1