클래스를 나타내는 오브젝트

변수 선언등에서 클래스명을 지정해, 그 클래스형의 변수를 준비할 수 있었습니다. 그러나, 클래스 메소드를 호출하기 위해서, 메세지식에서 지정한 클래스명은, 실은 클래스의 형태를 나타내고 있는 것은 아닙니다. 메세지식에서 지정하는 것은, 항상 메세지를 송신하는 앞의 오브젝트입니다. 즉, 메세지에서 지정해 있던 클래스명은 오브젝트입니다.

클래스가 인스턴스를 생성하도록 올바르게 컴파일 된 클래스는, 스스로의 정보를 나타내는 클래스 오브젝트를 보유하고 있습니다. 이 클래스 오브젝트는 Class 형태로서 변수에 보존하는 것도 가능합니다. 클래스 오브젝트가 존재하지 않는 값은 Nil 이라고 하는 정수로 표현됩니다. 통상,Nil은 NULL 와 같게 0 을 나타냅니다.

클래스 오브젝트를 취득하려면 , 인스턴스가 존재하는 경우는, Object 클래스의 class 인스턴스 메소드의 반환값으로부터 취득합니다. 인스턴스가 존재하지 않는 상태로, 클래스명이 판명되어 있는 경우, 클래스명을 직접 지정해 클래스 오브젝트를 취득할 수도 있습니다. 통상, 클래스명은 이름으로서 인식됩니다만,  메세지 송신지 오브젝트의 지정으로 클래스명을 지정했을 경우에 한해서, 이 클래스의 클래스 오브젝트로서 인식됩니다. 메세지에서, 클래스명으로 지정한 클래스 오브젝트를 돌려주게 하려면 , 클래스 오브젝트에 class 메세지를 송신합니다. 이 메소드는 다음과 같이 선언되고 있습니다.

- (Class)class;

이 메소드가 돌려준 값이 Class 형태의 오브젝트입니다. 클래스 오브젝트는 변수에 보존할 수 있기 위해, 클래스 메소드를 호출하는 메세지도, 변수에 보존되고 있는 오브젝트에 따라서 결과가 다른 다양성을 도입할 수 있습니다.

#import <stdio.h>
#import <objc/Object.h>

@interface Test : Object
+ (void)Write;
- (id)init;
@end

@implementation Test
+ (void)Write {
	printf("I love you... so please do not love me.\n");
}
- (id)init {
	printf("You can be whatever.\n");
	return [super init];
}
@end

int main() {
	Class testClass = [Test class];

	[testClass Write];
	[[testClass new] free];
	[testClass free];

	return 0;
}

이 프로그램의 [Test class] 의 Test는, 실은 클래스형은 아니고 클래스 오브젝트를 메세지식으로 지정하고 있습니다. 메세지식은 Test 클래스의 클래스 오브젝트를 돌려주어, testClass 변수에 오브젝트를 보존하고 있습니다. 이후, 이 testClass 변수는, 메세지식에서 Test 클래스 오브젝트와 같은 의미를 가집니다.

이 위력은, 그 후,Write 클래스 메소드를 실행하기 위해서 [testClass Write] 메세지식에서 실현될 수 있다고 하는 부분에서 확인할 수 있겠지요. 클래스 오브젝트를 가리키는 변수로부터 Write 메세지를 송신하고 있기 때문에, 이 호출은 지극히 동적인 호출이 됩니다. 물론,alloc이나 new 메세지를 송신하고, 클래스 오브젝트로부터 인스턴스를 작성할 수 있습니다. 변수를 바꿔 넣는 것만으로, 호출하는 클래스 메소드나 생성하는 인스턴스를 변경할 수 있기 위해, 유연한 프로그램을 실현하기 위해서 이용할 수 있습니다.

Posted by tklee

댓글을 달아 주세요