2015-07-08 5 views
2

В Delphi я запускаю унаследованный класс из базового класса, который уже создан. Я считаю, что это разделяет адреса базового класса между этими двумя классами, но дополнительные члены унаследованного класса получают дополнительную память, выделенную для них, но не инициализируются.Delphi Cast: утечка памяти?

Если освобожден общий базовый класс, это вызывает утечку памяти для членов класса Inherited?

Если да, то каков наилучший способ очистки унаследованных классов, если я хочу оставить базовый класс нетронутым?

program Project1; 

uses 
    SysUtils; 

type 
    TBase = class(TObject) 
    public 
    basemember : string ; 
    Constructor Create() ; 
    end; 

    TInherited = class(TBase) 
    public 
    inheritedmember : string ; 
    Constructor Create() ; 
    end ; 

    Constructor TBase.Create() ; 
    begin 
     basemember := 'Basemember' ; 
     Writeln ('basemember') ; 
    end ; 

    Constructor TInherited.Create() ; 
    begin 
     inheritedmember := 'inheritedmember' ; 
     Writeln ('inheritedmember') ; 
    end ; 

var 
    baseclass  : TBase; 
    castbaseclass : TInherited; 
begin 

    Writeln ('Base Class'); 
    baseclass := TBase.Create(); 

    Writeln (''); 
    Writeln ('Cast Inherited Class'); 
    castbaseclass := TInherited(baseclass); 

    baseclass.Free; //memory leak? 
    ReadLn; 

end. 

ответ

7

Здесь нет утечки памяти, но приведение в действие все еще не так.

Вы обеспокоены этой строки кода:

castbaseclass := TInherited(baseclass); 

С Delphi классов ссылочные типы, baseclass и castbaseclass являются оба указателя. Все, что вы сделали здесь, присваивается переменной указателя. Вы никогда не ссылаетесь на castbaseclass. Если вы это сделаете, тогда будет вероятность ошибок во время выполнения, потому что компилятор считает, что castbaseclass является экземпляром TInherited, но на самом деле это экземпляр менее специализированного класса, TBase.

Однако у вас есть глубокое недоразумение.

Я наследую класс из базового класса, который уже создан. Я считаю, что это разделяет адреса базового класса между этими двумя классами, но дополнительные члены унаследованного класса получают дополнительную память, выделенную для них, но не инициализируются.

Нет! Точно нет. Чтобы создать экземпляр TInherited, вы должны вызвать конструктор TInherited. Вы не можете создать экземпляр одного класса и ожидать, что он когда-либо превратится в другой класс. Тип экземпляра определяется раз и навсегда, когда он создается. Память для экземпляра выделяется при создании экземпляра и ни в какое другое время.

Итак, если вы хотите TInherited, создайте его. Если вы хотите создать TBase, создайте его. Но вы не можете создать TBase и изменить его тип на TInherited. Вы можете создать TInherited, а затем присвоить его переменной типа TBase. Это потому, что TInherited происходит от TBase.

Таким образом, вы можете написать:

var 
    base: TBase; 
    inherited_: TInherited; // _ because inherited is a keyword 
.... 
inherited_ := TInherited.Create; 
base := inherited_; 

Но вы не можете писать:

var 
    base: TBase; 
    inherited_: TInherited; 
.... 
base := TBase.Create; 
inherited_ := base; 
+0

Я предполагаю, чтобы получить унаследованные переменные члены должны быть выделены, унаследованный класс должен быть создан с помощью 'new' - но тогда есть ли способ, чтобы базовый компонент унаследованного класса указывал на уже существующий экземпляр базового класса? – Retiarius

+0

Нет на обоих счетах. Вы выделяете экземпляры классов вызовом конструкторов, а не вызовом new. И нет, вы не можете накладывать один экземпляр на другой. Ну, теоретически может быть возможно с какой-то формой распределения пользовательских экземпляров. Но это было бы безумным и непрактичным. Может быть, я даже не должен был упоминать об этом! –

+0

У вас явно есть неправильная ментальная модель для всего этого. Я рекомендую вам потратить немного времени на исправление этой ментальной модели. –