2017-06-01 68 views
1

我希望其他对象中包含的对象不必分配内存。例如,在德尔福我可以这样写:如何在不分配内存的情况下构造对象?

type 
    TTest = class 
    obj1: tobject1; 
    obj2: tobject2; 
    constructor Create; 
    destructor Destroy; override; 
    end; 

constructor TTest.Create; 
begin 
    inherited; 
    obj1 := tobject1.Create; 
    obj2 := tobject2.Create; 
end; 

destructor TTest.Destroy; 
begin 
    obj1.Free; 
    obj2.Free; 
    inherited; 
end; 

类似C++代码是这样的:

class TTest { 
    tobject1 obj1; 
    tobject2 obj2; 
}; 

我想专注于不同的是如何在Delphi版本有3个内存分配而在C++版本中只有1个。有没有办法在德尔福只有一个内存分配一个完整的对象及其子对象,就像在C++中一样?

更新:完整的C++测试代码:

class tobject1 { public: int aaa; }; 
class tobject2 { public: int bbb; }; 

class TTest { 
    tobject1 obj1; 
    tobject2 obj2; 
public: 
    void doThing() { obj1.aaa = obj2.bbb; }; 
}; 

int main() 
{ 
    {TTest * test = new TTest; test->doThing(); delete test; } 
    {TTest test; test.doThing(); } 

    return 0; 
} 

反汇编代码:

{TTest * test = new TTest; test->doThing(); delete test; } 
013D182E push  8 
013D1830 call  operator new (013D1299h) 
013D1835 add   esp,4 
013D1838 mov   dword ptr [ebp-0E4h],eax 
013D183E mov   eax,dword ptr [ebp-0E4h] 
013D1844 mov   dword ptr [ebp-8],eax 
013D1847 mov   ecx,dword ptr [ebp-8] 
013D184A call  TTest::doThing (013D133Eh) 
013D184F mov   eax,dword ptr [ebp-8] 
013D1852 mov   dword ptr [ebp-0F0h],eax 
013D1858 push  8 
013D185A mov   ecx,dword ptr [ebp-0F0h] 
013D1860 push  ecx 
013D1861 call  operator delete (013D104Bh) 
013D1866 add   esp,8 
{TTest test; test.doThing(); } 
013D1869 lea   ecx,[ebp-18h] 
013D186C call  TTest::doThing (013D133Eh) 

C++对象只需要1个内存分配为包含子对象的新对象,甚至如果对象放在堆栈而不是堆上,则为0内存分配。

更新:完整的Delphi测试代码:

program Project1; 

type 
    tobject1 = class 
    aaa: longint; 
    end; 

    tobject2 = class 
    bbb: longint; 
    end; 

    TTest = class 
    obj1: tobject1; 
    obj2: tobject2; 
    constructor Create; 
    destructor Destroy; override; 
    procedure doThing; 
    end; 

constructor TTest.Create; 
begin 
    inherited; 
    obj1 := tobject1.Create; 
    obj2 := tobject2.Create; 
end; 

destructor TTest.Destroy; 
begin 
    obj1.Free; 
    obj2.Free; 
    inherited; 
end; 

procedure TTest.doThing; 
begin 
    obj1.aaa := obj2.bbb; 
end; 

var 
    test: TTest; 

begin 
    test := TTest.Create; 
    test.doThing; 
    test.Free; 
end. 

拆分配代码:

Project1.dpr.35: test := TTest.Create; 
0040A0F4 B201    mov dl,$01 
0040A0F6 A19C924000  mov eax,[$0040929c] 
0040A0FB E8DCF2FFFF  call TTest.Create 
0040A100 A3F8F44000  mov [$0040f4f8],eax 
Project1.dpr.36: test.doThing; 
0040A105 A1F8F44000  mov eax,[$0040f4f8] 
0040A10A E865F3FFFF  call TTest.doThing 
Project1.dpr.37: test.Free; 
0040A10F A1F8F44000  mov eax,[$0040f4f8] 
0040A114 E8DBA1FFFF  call TObject.Free 

拆解创建代码代码:

Project1.dpr.16: obj1 := tobject1.Create; 
004093F4 B201    mov dl,$01 
004093F6 A144914000  mov eax,[$00409144] 
004093FB E8C4AEFFFF  call TObject.Create 
00409400 8B55FC   mov edx,[ebp-$04] 
00409403 894204   mov [edx+$04],eax 
Project1.dpr.17: obj2 := tobject2.Create; 
00409406 B201    mov dl,$01 
00409408 A1F0914000  mov eax,[$004091f0] 
0040940D E8B2AEFFFF  call TObject.Create 
00409412 8B55FC   mov edx,[ebp-$04] 
00409415 894208   mov [edx+$08],eax 

此德尔斐对象需要3个的内存分配用于包含的新对象s 2个子对象。如果使用对象而不是记录(因为它们不支持继承,所以它们完全不一样),是否有可能像C++一样减少一个分配(或者如果放在堆栈中,甚至是0)?

+0

在C++版本中也有三种内存分配。在'TTest'构造函数中调用'tobject1'和'tobject2'的默认构造函数。 Delphi没有这个机制,所以你必须手动创建对象。 – Ari0nhh

+0

在子对象上调用默认构造函数和析构函数,但不是新建和删除,C++版本仅为整个对象组合分配一块内存。 – Mardulu

+0

我从来没有尝试过,但你可以玩重写[TObject.NewInstance](http://docwiki.embarcadero.com/Libraries/Seattle/en/System.TObject.NewInstance)。但请注意,这不是Delphi的方式。 –

回答

2

在Delphi中,类是引用类型,因此在实例化时总是会产生堆位置。所以你不能实现你希望使用类的内存布局。

相反,记录是值类型。如果您将两种嵌入式类型放入记录中,则会根据需要布置内存,并且只会有一个堆分配。

+1

我认为你的第一段你的意思是“不能”?我希望能够像你的第二段那样做,但也能够使用嵌入类型的继承,但如果没有,那就好了。 – Mardulu

+0

值的继承可让您打开[对象切片](https://en.wikipedia.org/wiki/Object_slicing)。是的,我更正了第一段,谢谢。 –

+0

您可以将类型声明为'object'而不是'class'或'record'。一个'object'可以在堆栈上分配,并且嵌套的对象将全部在一个分配中,类似于C++代码。然而,'object'是为了向后兼容而提供的旧语法,在这种情况下'记录'类型将是首选。 –

0

你在这里想错了。 C++和Delphi一样知道构造函数和析构函数,你只是没有在你的C++定义中定义它们。

而且不,你不能为该实例分配内存而不能分配一个类的实例。这与Delphi和C++没有什么不同。

+0

在C++版本中,当创建一个新的TTest对象时,整个对象将只有一个内存分配,并为主对象和每个子对象调用构造函数。我希望Delphi中的这种行为。 – Mardulu

+0

@Mardulu:在Delphi中,这不是* classes *的工作方式。我可能不应该提及它们,但旧的Turbo Pascal'object'类型更像C++类,可以用作值类型,但即使它们不是自动构建的。请注意,这些旧式'对象'类型已被弃用且不再受到完全支持。 –

相关问题