|
: 하지만 제가 생성한 코드는 new없이 global하게 pointer만을 선언하고 사용하고 있습니다..
: 즉,
:
: TMyClass *MyClass; 이렇게 선언하고
:
: MyClass->Method1(); 이렇게 쓰고 있습니다..
:
: TObject를 상속받고 vcl.hpp를 사용도 하고 있습니다..
: 그런데 객체생성없이 수행이 된다라는것이 이상한 겁니다...
: 왜 런타임시에 에러가 안날까요?
그건, 해당 인스턴트의 자료에 액세스하지 않았기 때문입니다.
첨부 파일에 있는 TTest1 클래스에는 일단 virtual 메서드가 없습니다.
TTest1 *Test1; //파일 수준에서 선언한 전역변수; NULL로 초기화됨
TTest1* 형의 NULL 포인터에 대해 ShowMsg()를 호출하면 TTest 클래스(not Instance)의 메서드 테이블에 있는 ShowMsg를 호출합니다. ShowMsg의 상대 주소를 구하는 것은 컴파일 또는 링크 시에 하게 됨.
이 함수를 호출할 때는 먼저 CPU의 특정 레지스터에 인스턴스의 포인터를 저장해두고 함수를 호출할 것입니다(추측).
(위의 경우 Test1의 값, NULL을 레지스터에 저장)
그러한 후 호출된 함수로 실행 지점이 옮겨가면 호출된 함수에서는 해당 레지스터에서 인스턴스 포인터(즉, this)를 가져옵니다. (이러한 작업을 하는 코드 생성은 컴파일러가 자동으로 할 것입니다)
이 인스턴스 포인터로 하는 일은 가상함수 테이블과 자신만의 데이터 멤버에 액세스하는 것입니다.
만약, 가상함수(순수가상 말고)를 선언해두고 해당 함수를 호출하면 오류가 발생할 것입니다.
왜냐하면, 인스턴스 포인터를 통해 vtable를 액세스하여 해당 함수를 찾아와야 하는데 가리키는 메모리가 엉뚱한 곳이기 때문에 함수의 번지도 엉뚱한 것이고 해당 번지로부터 시작되는 함수의 내용도 엉뚱한 것이 됩니다. vtable을 가리키는 포인터는 인스턴스가 저장된 시작번지에 위치함.
가상함수의 예는 멤버변수들(함수 말고)에 대해서도 같습니다.
각 클래스에 대해서 멤버 함수들은 하나씩만 있으면 됩니다.
각 인스턴스마다 함수를 만들 필요는 없는 것이지요, 낭비이니까요.
그러면 인스턴스와 함수는 어떻게 연결하느냐 하면, 멤버 함수들을 모두 컴파일 한 다음 이 들의 번지를 각 클래스별로 임시의 함수 테이블에 저장해둡니다.
그러한 후, Test1->ShowMsg()와 같이 클래스 멤버 함수를 호출하는 것이 발견되면,
해당 클래스의 함수테이블에서 해당 함수의 번지를 가져와서 이 번지로 부터 시작되는 코드를 실행시키는 코드를 작성합니다. 물론, 함수의 입장에서는 this 포인터가 되는 Test1의 값도 레지스터에 저장.
위와 같이 볼 때 함수 테이블은 실행 파일에 필요가 없고, vtable(가상함수 테이블)은 실행시간에 필요하므로 실행 파일에 위치하게 됩니다.
TTest1 *Test1=NULL;
Test1->ShowMsg(); 의 처리는 아래와 같을 것입니다.
TTest 클래스의 메서드 테이블에서 ShowMsg의 번지를 가져옴, 이 번지를 A1이라 합시다.
매개변수가 없으므로 stack에는 아무것도 push하지 않음.
특정 레지스터에 Test의 값 즉 NULL을 저장함.
call 또는 jump A1.
A1의 번지로 실행지점이 옮겨가면 레지스터에서 this 포인터를 꺼내고 아규먼트들을 스택에서 pop하여 매개 변수들의 값을 설정.
사용자 작성 코드 실행
반환
위의 작업을 하는 코드는 컴파일러와 링커가 생성하게 됨.
친구들 님이 쓰신 글 :
: 먼저 답변해주셔서 감사합니다...
:
: 님께서 말한대로 struct와 동일하게 사용된다면
: TMyClass MyClass;
: 이렇게 선언하고 MyClass.Method1() 이렇게 쓴다는것이 이해가 됩니다..
:
: 컴파일 타임에 메모리에 올라간다고 했으니깐요...
:
: 하지만 제가 생성한 코드는 new없이 global하게 pointer만을 선언하고 사용하고 있습니다..
: 즉,
:
: TMyClass *MyClass; 이렇게 선언하고
:
: MyClass->Method1(); 이렇게 쓰고 있습니다..
:
: TObject를 상속받고 vcl.hpp를 사용도 하고 있습니다..
: 그런데 객체생성없이 수행이 된다라는것이 이상한 겁니다...
: 왜 런타임시에 에러가 안날까요?
:
: test코드를 zip으로 첨부합니다...
:
: Unit2.cpp가 수행되는 이유가 무엇얼까요?
:
: 이유를 알아야...이 코드를 계속 놔두어도 될지 아니면
: 싹 뜯어고칠지 정해야 되기때문에....많은 reply부탁 드립니다...
:
:
:
:
: 황경록 님이 쓰신 글 :
: : 클래스 자체가 꼭 new 로 생성을 해야만 메모리가 할당되는 것은 아닙니다.
: :
: : class TMyClass
: : {
: : Method1()
: : ...
: : }
: :
: : 으로 만드신 베이스 클래스라면 일반 스트럭처와 동일하게 사용할 수 있습니다.
: : 스트럭처와 클래스는 분명 큰 차이점이 있지만 그 기반은 동일하니까요.
: :
: : TMyClass MyClass;
: :
: : MyClass.Method1() 의 형식으로 호출이 가능하며 메모리 누수와는 관계가 없습니다.
: : 그리고 MyClass 는 컴파일 시에 TMyClass 만큼의 메모리가 할당되며 프로그램 종료시에
: : 해제됩니다.
: :
: : 보통 빌더에서 new 를 사용해서 객체를 생성하는 것은 델파이에서 온 VCL Class 때문입니다.
: : VCL 클래스는 반드시 new 를 통한 메모리 할당을 통해서 이용해야 합니다.
: : VCL 의 구조적 특성( ^^ 예전에 읽었는데 영문이라 대충 읽어서 ... ) 때문입니다.
: :
: : 만약 클래스를 VCL 클래스 기반으로 만든다면 VCL 베이스 클래스인 TObject 를
: : 상속받으시면 됩니다.
: :
: : class TMyClass : public TObject
: : {
: : Method1()
: : ...
: : }
: :
: : TMyClass* pMyClass = new TMyClass();
: : pMyClass->Method1();
: :
: : 이 되는 것이죠....
: :
: : 친구들 님이 쓰신 글 :
: : : 답변 감사합니다...위 답변을 보고 코드를 수정을 했습니다....
: : :
: : : 근데...제가 의문시되는것은 new로 생성을 하지 않은 코드가 돈다는 겁니다...
: : : 아래 코드는 project option의 autocreate form도 아닙니다...
: : : 즉, new 해주는 부분이 없습니다..그냥 function call하는것처럼 쓰고 있습니다..
: : : 물론 객체를 생성하면 Method called on invalid object라는 코드가드에서 뿌리던 메시지는 사라집니다..
: : :
: : : 지금까지 객체생성없이 잘 사용했기때문에 만약 문제가 있다면...
: : : 모든 소스를 바꾸어야 하는 문제가 생기기 때문에 저한테는 매우 중요한 문제입니다..
: : :
: : : 아무쪼록 이런 경험이 있으시면 reply감사하겠습니다...
: : :
: : : 그럼...
: : :
: : :
: : :
: : :
: : :
: : :
: : : 이상해 님이 쓰신 글 :
: : : : 코드 가드를 이용했더니 다음과 같은 에러를 뱉어냅니다...
: : : :
: : : : Error 00164. 0x100C00 (Thread 0x0CA0):
: : : : Method called on invalid object: Attempt to access 4 byte(s) at 0x00000000.
: : : : Call Tree:
: : : : 0x00414B8A(=AAAA.exe:0x01:013B8A) C:\test\EScnro.cpp#77
: : : : ===> 에러가 EScnro에서 발생해서 AScnro까지 던져주고 있습니다...
: : : : 0x0043E67D(=AAAA.exe:0x01:03D67D) C:\test\DScnro.cpp#289
: : : : 0x004497E0(=AAAA.exe:0x01:0487E0) C:\test\CScnro.cpp#132
: : : : 0x0044A9E7(=AAAA.exe:0x01:0499E7) C:\test\BScnro.cpp#293
: : : : 0x0044A30E(=AAAA.exe:0x01:04930E) C:\test\AScnro.cpp#229
: : : : 0x400EE4E7(=vcl60.bpl:0x01:03D4E7)
: : : : ------------------------------------------
: : : : 위와 같은 에러를 수백개 뱉어내네요....메모리도 콸콸 세고.......-_-;;
: : : : 문제는 invalid object라는 에러인데.... EScnro.cpp는 객체를 생성을 하지않고 쓰고 있습니다
: : : : 여기서 제가 의문이 드는것은 객체 생성을 하지 않고 다음과 같이 사용했을때
: : : : 런타임시에 객체가 없다고 에러를 뱉어야 하는데 어떻게 빌더가 에러없이 도는지 이해가 가지 않습니다...
: : : :
: : : : ============header 파일====================
: : : :
: : : : #ifndef EScnroH
: : : : #define EScnroH
: : : :
: : : : //---------------------------------------------------------------------------
: : : : class TEScnro : public TObject
: : : : {
: : : : private: // User declarations
: : : : public: // User declarations
: : : : __fastcall TEScnro();
: : : : AnsiString __fastcall ShowMessage(AnsiString msg);
: : : : };
: : : : //---------------------------------------------------------------------------
: : : : extern PACKAGE TEScnro *EScnro;
: : : : //---------------------------------------------------------------------------
: : : :
: : : : #endif
: : : :
: : : :
: : : : ============cpp 파일====================
: : : : #include "EScnro.h"
: : : :
: : : : //---------------------------------------------------------------------------
: : : : #pragma package(smart_init)
: : : :
: : : : TEScnro *EScnro;
: : : :
: : : : __fastcall TEScnro::TEScnro()
: : : : {
: : : : }
: : : :
: : : : AnsiString __fastcall TEScnro::ShowMsg(AnsiString msg)
: : : : {
: : : : return "객체생성없이 왜 도냐?";
: : : : }
: : : :
: : : : ============================================================================
: : : :
: : : : 만약 일반 c처럼 생각해서 객체 없이 함수만 호출한다고 한다면...
: : : :
: : : : TEScnro *EScnro; ==> TEScnro EScnro; 이렇게 포인터 없이 사용해야하는거 아닌가요??(struct 사용할때처럼...)
: : : : 그리고 EScnro->ShowMessage(msg); 이렇게 사용하는게 아니라
: : : : EScnro.ShowMessage(msg);로 사용하는거 아닌가요??
: : : :
: : : : 위와 같이 코딩하면 왜 수행이 되는지 알려주시면 감사하겠습니다...
: : : : 또한 메모리 누수 현상과도 관계가 있는지요??
: : : :
: : : : 조그만 도움이라도 부탁합니다...ㅜㅜ
|