Тонкости реализации

Dec 10, 2008 10:27

Вдогонку к.

Для начала напишем одну небольшую программу на C++. Два класса, один порождается от другого, в родительском классе реализован статический метод m1.


class c1 {
public:
static void m1() { cout << "c1.m1\n"; }
};
class c2 : public c1 {
};

void main(void) {
c1 o1;
c2 o2;
// вызываться метод m1 может по-разному, и от класса, и от объекта
c1::m1();
c2::m1();
o1.m1();
o2.m1();
}

Вот та же самая структура на Delphi:

program test1;

{$APPTYPE CONSOLE}

uses
SysUtils;

type
c1 = class
class procedure m1;
end;
c2 = class(c1)
end;

class procedure c1.m1;
begin
WriteLn('c1.m1');
end;

var
o1: c1;
o2: c2;
begin
o1:=c1.Create;
o2:=c2.Create;
c1.m1;
c2.m1;
o1.m1;
o2.m1;
end;

И вывод программ будет одинаков (чего и следовало ожидать). Интереснее
получается, если добавить в классы еще по одному статическому методу (или, для
Дельфи, методу класса), который будет вызываться из m1.

class c1 {
public:
static void m1() { cout << "c1.m1\n"; }
static void m2() { cout << "c1.m2\n"; }
};
class c2 : public c1 {
public:
static void m2() { cout << "c2.m2\n"; }
};

Функция main() осталась той же.

На Дельфи будут внесены такие изменения:

type
c1 = class
class procedure m1;
class procedure m2;
end;
c2 = class(c1)
class procedure m2;
end;

class procedure c1.m1;
begin
WriteLn('c1.m1');
end;

class procedure c1.m2;
begin
WriteLn('c1.m2');
end;

class procedure c2.m2;
begin
WriteLn('c2.m2');
end;

Вывод обеих программ будет одинаковый:

c1.m1
c1.m2
c1.m1
c1.m2
c1.m1
c1.m2
c1.m1
c1.m2

Однако в Дельфи методы класса тоже могут быть виртуальными. Переопределим в дельфовской программе методы m2 так:

type
c1 = class
class procedure m1;
class procedure m2; virtual;
end;
c2 = class(c1)
class procedure m2; override;
end;

И теперь вывод дельфовской программы будет

c1.m1
c1.m2
c1.m1
c2.m2
c1.m1
c1.m2
c1.m1
c2.m2

Заметим, что там, где мы вызываем процедуру m1 от класса c2 или от объекта o2, из c1.m1 вызывается с2.m2.

Еще интереснее получается, когда мы вызываем методы от переданных в процедуру ссылок на объект. Чтобы попробовать это, изменим нижнюю часть дельфовской программы (после метода c2.m2):

procedure proc(r: c1);
begin
r.m1;
end;

var
o1: c1;
o2: c2;
begin
o1:=c1.Create;
o2:=c2.Create;
o1.m1;
o2.m1;
proc(o1);
proc(o2);
o1.Free;
o2.Free;
end.

Даже для переданного по ссылке (а объекты в Delphi - это всегда ссылки) объекта виртуальность метода класса работает.

А совсем интересно станет, если мы будем вместо ссылки на объект передавать в процедуру ссылку на класс. Для этого после определения классов определим и тип ссылки на класс:

type
c1 = class
class procedure m1;
class procedure m2; virtual;
end;
c2 = class(c1)
class procedure m2; override;
end;
cls = class of c1; // это и есть ссылка на класс

В процедуре proc поменяем тип параметра r на cls.

procedure proc(r: cls);
begin
r.m1;
end;

И в proc будем передавать не объекты, а классы:

proc(c1);
proc(c2);

Т.е. вместо o1 передаем c1, и вместо o2 - c2.

И снова в выводе программы там, где мы передаем c2, вызывается метод правильного класса c2.m2.

programming, cpp, delphi

Previous post Next post
Up