최근 인터넷에서 한 네티즌이 '객체 포인터가 사용 가능한지 어떻게 확인하나요?'라고 묻는 것을 봤습니다. 즉, 객체 포인터가 실제 사용 가능한 객체 인스턴스를 가리키는지 여부를 확인하는 방법은 무엇입니까? 실제로 이것은 문제가 되지 않습니다. 프로그래머는 유효하지 않은 포인터에 접근하지 않도록 자신의 프로그램을 제어할 수 있어야 하며, 모든 객체 인스턴스의 생성과 소멸은 프로그래머의 통제 하에 있기 때문입니다. 그리고 객체 포인터가 사용 가능한지 여부를 확인할 수 있는 직접적인 방법이 없더라도 다른 간접적인 방법(예: 일부 식별자 사용 등)을 통해 수행할 수도 있습니다(예를 들어 객체 인스턴스를 삭제할 때 개체 포인터의 포인터가 nil입니다.) 하지만 위에서 언급한 두 가지 사항을 제쳐두고 델파이에서 개체 포인터를 사용할 수 있는지 여부를 확인할 수 있는 방법이 있는지 연구하면 어떻게 될까요?
오브젝트 파스칼에서 클래스는 두 가지 유형의 메소드를 가질 수 있습니다. 하나는 객체 메소드(Object Method)이고 다른 하나는 클래스 메소드(Class Method)입니다. 소위 객체 메소드는 메소드의 정의가 객체(또는 인스턴스)에 대한 것이므로 메소드 호출은 객체(또는 인스턴스)를 기반으로 해야 함을 의미합니다. 예를 들어 클래스의 소멸자 Destroy는 객체입니다. 메소드(사실 우리가 사용하는 대부분의 메소드는 객체 메소드입니다). 클래스 메소드는 객체의 클래스를 기반으로 하는 메소드 정의를 참조하므로 메소드 호출이 클래스의 생성자 Create와 같은 특정 객체 인스턴스를 기반으로 할 필요는 없습니다. 이것은 우리에게 영감을 줍니다. 객체 포인터가 사용 가능한지 여부를 결정하는 것은 다음 단계를 통해 수행되는 것으로 보입니다. 먼저 객체 포인터가 nil인지 확인할 수 있습니다. 그렇다면 작업이 완료된 것이며, 그렇지 않은 경우에는 객체의 객체 메서드를 실행하여 잘못된 메모리 액세스와 같은 예외가 있는지 확인합니다. 이는 객체가 사용 가능한지 여부를 확인하는 데 사용됩니다. 다음 코드를 사용하여 아이디어를 확인하세요.
var
개체: TObject;
시작하다
Obj := TObject.Create; //1.
Obj.Free; //2. 방금 생성한 객체를 해제하면 이때 메모리가 재활용됩니다.
Obj = nil이면 //3. 포인터가 비어 있는지 확인합니다(객체가 비어 있기 때문에 이 단계는 종종 실패합니다).
//해제되면 Delphi는 자동으로 객체 포인터를 비우지 않습니다)
ShowMessage('객체 포인터를 사용할 수 없습니다.')
또 다른
시작하다
노력하다
Obj.ClassType = TObject이면 //4. TObject의 객체 메소드를 호출합니다.
ShowMessage('객체 유형은 TObject입니다.');
제외하고
ShowMessage('객체 포인터를 사용할 수 없습니다.')
끝;
끝;
끝;
위 코드를 실행하면 Obj.Free가 실행되더라도 Obj.ClassType을 계속 사용할 수 있음을 알 수 있습니다. 이는 모든 객체 메소드가 액세스 가능하기 위해 객체 인스턴스에 의존해야 하는 것은 아니라는 것을 보여줍니다. 그 이유는 이 객체 메서드가 객체 인스턴스가 요청한 메모리에 액세스할 필요가 없기 때문입니다. 이러한 의미에서 TObject.ClassType 메소드는 실제 객체 메소드처럼 보이지 않고 오히려 클래스 메소드와 유사합니다.
위의 코드를 실행하면 개체가 Free 메서드를 실행할 때 개체가 생성될 때 적용한 모든 메모리만 해제할 뿐 개체 포인터 자체의 값에는 영향을 주지 않는다는 사실도 알 수 있습니다. 객체 포인터는 여전히 원래 메모리 주소를 가리킵니다. 동시에 일부 개체 메서드(예: ClassType) 구현의 특수성으로 인해 개체가 해제된 경우에도 개체 메서드 호출의 결과는 여전히 정확합니다.
요약하면, 객체 포인터가 사용 가능한 것으로 판단될 수 있는지 여부는 객체 포인터가 속한 클래스가 객체 인스턴스 메모리에 액세스하는 방법을 제공하는지 여부에 따라 결정된다는 결론을 내릴 수 있습니다. 속성이 됩니다. 그렇다면 현재 각 카테고리의 상황은 구체적으로 어떤가요?
TObject, 이 클래스는 모든 클래스의 조상 클래스이므로 판단할 방법이 없습니다.
TObject에서 파생된 TPerpersist는 객체 인스턴스 생성 시 추가 메모리를 적용할 필요가 없으므로 판단할 방법이 없습니다.
TPersistant에서 파생된 TComponent는 객체 인스턴스 생성 시 적용하기 위해 추가 메모리가 필요한 속성을 많이 추가하므로 이론적으로 판단됩니다. 코드는 다음과 같습니다:
함수 ComponentExists(AComponent: TComponent): 부울;
시작하다
노력하다
AComponent.Hasparent; //참고: 이 문장은 "AComponent.Tag;"일 수도 있습니다.
//또는 "AComponent.Name"
결과 := 참;
제외하고
결과 := 거짓;
끝;
끝;
ComponentExists를 호출하면 객체 포인터가 해제되었는지 또는 nil로 설정되었는지에 관계없이 TComponent 유형의 객체 포인터가 사용 가능한지 여부를 알 수 있습니다.
TControl, TWinControl, TButton 등과 같은 다른 클래스의 경우 TComponent에서 파생되는 한 TComponent의 판단 방법이 계속 적용됩니다.
다른 사용자 정의 클래스가 있습니다. 판단할 수 없는 클래스(예: TObject 및 TPersistant)에서 직접 파생되었지만 인스턴스화 중에 메모리 적용이 필요한 속성이 없으면 달리 판단할 방법이 없습니다. 가능합니다. 예에 따르면:
다음과 같이 정의된 TPerson 클래스가 있다고 가정합니다.
TPerson = 클래스(TObject)
사적인
FSex: TSex; // TSex는 열거형의 성별입니다.
FFirstName: 문자열;
FLastName: 문자열;
//…
공공의
속성 섹스: TSex 읽기 FSex 쓰기 FSex;
속성 FirstName: 문자열 읽기 FFirstName 쓰기 FFirstName;
속성 LastName: 문자열 읽기 FLastName 쓰기 FLastName;
//…
끝;
그런 다음 TPerson 유형의 포인터 Person에 대해 다음 코드를 사용하여 포인터를 사용할 수 있는지 확인할 수 있습니다.
노력하다
사람.성별;
//또는 Person.FirstName;
//또는 Person.LastName;
result := True; //포인터를 사용할 수 있습니다.
제외하고
result := False;//포인터를 사용할 수 없습니다.
끝;
위에서 논의한 것은 단지 기술적인 가능성일 뿐입니다. 제가 강조하고 싶은 점은 좋은 방법이 있어도 자주 하는 것은 권장하지 않는다는 점입니다. 엄격한 논리를 갖춘 프로그램은 유효하지 않은 포인터에 대한 액세스를 방지할 수 있어야 하기 때문입니다.
더 많은 기사