오브젝트 파스칼
오브젝트 파스칼(Object Pascal)은 기존의 파스칼(Pascal) 언어에 객체 지향 개념을 포함하여 발전시킨 프로그래밍 언어 이다. 주로 델파이(Delphi) 언어로도 잘 알려져 있다.
목차
개요
오브젝트 파스칼은 애플 매킨토시의 전신인 애플 리자용으로 개발한 오브젝트 파스칼 컴파일러가 시초이며 가장 널리 알려진 오브젝트 파스칼의 변종은 볼랜드/코드기어 사의 델파이에서 사용되는 델파이 프로그래밍 언어가 있다. 델파이에서 사용된 오브젝트 파스칼은 표준 파스칼에 비해 많은 진보가 있는 언어이다. 파스칼은 최초의 탑-다운(top-down) 디자인과 구조적 프로그래밍을 가르치기 위해 개발된 언어이다. 그렇기 때문에 가장 많은 수의 대학에서 프로그래밍 언어의 표준으로 이를 이용해 강의하곤 했다. 그러던 중 볼랜드가 터보 파스칼을 발표하게 되었고 이해하기 어려운 C 코드에 비해 직관적이면서도 깨끗한 터보 파스칼은 당시에 상당한 반향을 일으키며 터보 C 와 함께 시장의 양대 언어로 자리 잡았다. 파스칼이 객체지향형 프로그래밍 언어의 기능을 추가하게 된 것은 터보 파스칼 5.5버전으로, 이때부터 조금씩 진보된 환경에서 변화를 시도했다. 이후 델파이 1.0이 발표되면서 명실상부한 객체지향형 파스칼로서 세상에 모습을 드러내게 된다.[1]
특징
- 클래스 및 객체
클래스는 일종의 데이터형이며, 객체는 클래스가 실제로 메모리에서 인스턴스화 된 것이다. 오브젝트 파스칼과 C++, 자바는 모두 클래스에 바탕을 둔 언어다. 각각의 객체들은 직접 정의되지 않고, 일단 클래스로 정의된 후 객체는 클래스에 대한 한의 인스턴스로 나타나는 형태를 가지고 있다. 클래스틑 객체와 1:n의 관계를 맺게 된다. 클래스는 코드를 메소드의 형태로 저장하며, 여러 객체들과 이를 공유하게 된다. 각 객체는 자신의 데이터 필드를 저장하게 되며, 이것으로 클래스와 객체가 구별된다. 객체 내의 필드는 원시적인 데이터형이거나 객체일 수 있다. 정상적으로 각 객체는 클래스에서 선언된 데이터 필드의 복사본을 자신의 것으로 가지고 있다. 오브젝트 파스칼은 동적(dynamic) 객체만을 지원한다. 로컬, 전역 객체가 선언될 수 있지만, 이들은 단지 레퍼런스로서 데이터 세그먼트나 스택에 저장된다. 객체 자체는 반드시 직접 생성해서 항상 힙에 저장해야 한다. 오브젝트 파스칼은 기본적으로 사용자 정의 메모리 할당 루틴을 제공하지는 않는다. 그렇지만, 자동 garbage cllection 은 지원하지 않으므로, 프로그래머가 각 개체를 동적으로 생성한 경우 이를 제거할 필요가 있다.[2]
- 생성자
프로그래밍 언어에서 생성자(Constructors)는 객체를 초기화하게 된다. 오브젝트 파스칼에서는 'constructor'라는 키워드를 사용해서 생성자를 정의한다. 메소드 오버 로딩을 지원하지 않지만, 생성자가 여러 가지 이름을 가질 수 있어서 여러 개의 생성자를 가질 수 있다. 오브젝트 파스칼에서는 각각의 클래스가 디폴드 Create 생성자를 가지고 있게 되는데, 이 생성자는 기본적인 기초 클래스에서 상속받게 된다.[2]
- 파괴자
파괴자(Destructor)는 생성자와 반대되는 일을 한다. 즉, 객체가 메모리에서 해제될 때 호출되며 생성자에 의해 할당된 리소스를 해제하는 역할을 하게 된다. 오브젝트 파스칼의 파괴자는 표준 가상 파괴자인 'Destroy'를 이용하는데, 이 파괴자는 자유(Free) 메소드에 의해 호출된다. 모든 객체가 동적으로 처리되기 때문에, 일단 객체가 생성되면 그 객체의 소유주(owner) 객체가 파괴될 때 자동으로 자유 메소드가 호출된다. 이론적으로 여러 개의 파괴자를 선언할 수 있다.[2]
- 클래스 캡슐화
클래스 캡슐화의 레벨을 지정하는 지시어로 프라이베이트(private), 프로텍티드(protected), 퍼블릭(public)이 사용된다. 프라이베이트, 프로텍티드 키워드는 다른 유닛일 경우에는 접근할 수 없지만 같은 유닛(같은 소스 코드 파일)에 있으면 접근이 가능하다. 그밖에, 디자인 시에 필드의 값을 보고, 편집할 수 있는 프로퍼티를 제공한다. 프로퍼티는 간접적으로 객체의 필드에 접근하기 때문에, 캡슐화 개념을 충실하게 지키고 있다. 프로퍼티는 데이터 필드에 대한 단순한 레퍼런스일 수도 있고, 참조 무결성을 유지하는 등의 보다 여러 가지 조작을 가할 수 있는 함수를 호출하는 것일 수도 있다.[2]
- 유닛 패키지
오브젝트 파스칼의 경우에는 각각의 소스 코드 파일을 유닛이라고 한다. 이러한 유닛은 크게 나누어 인터페이스(interface), 임플러먼테이션( implementation) 이라는 2개의 파트로 이루어져 있다. 인터페이스는 클래스의 정의와 메소드에 대한 선언 부분을 포함하며, 임플러먼테이션은 인터페이스에서 선언한 메소드의 구현 부분이 위치하게 된다. 다른 파일에서 선언된 인터페이스 부분을 'uses' 키워드를 통해 접근할 수 있다.[2]
- 메소드 및 데이터
객체지향 언어는 일반적으로 특정 객체에만 해당하지 않고, 클래스에 전반적으로 적용할 수 있는 메소드와 데이터를 허용한다. 클래스 메소드는 클래스의 객체와 클래스 자체에서 호출할 수 있으며, 클래스 데이터는 각각의 객체에 의해 복제되지 않고, 공통으로 사용되는 데이터를 말한다. 이들은 다른 말로 정적 메소드(static method), 정적 데이터(static data)라고도 한다. 오브젝트 파스칼은 클래스 메소드만 지원한다. 클래스 메소드는 'class' 키워드에 의해 지정될 수 있다. 클래스 데이터는 직접 지원하지 않고, 대신 클래스를 정의한 유닛에 프라이베이트 전역 변수를 추가해서 이 기능을 대치한다.[2]
- 전체 클래스
일부 객체지향 언어에서는 최소한 하나의 기초 클래스를 가지는 경우가 있다. 이러한 클래스는 모든 클래스에서 동일하게 가져야 하는 기복적인 특징 들을 가지고 있다. 즉, 모든 클래스는 가장 기본적인 기초 클래스를 상속받는 것이다. 이러한 개념은 스몰토크에서부터 시작된 것으로 비교적 많은 객체지향 언어에서 채택되고 있는 방식이다. 오브젝트 파스칼은 티오피젝트(TObject) 클래스를 공통의 조상으로 가진다. 오브젝트 파스칼은 기본적으로 다중 상속을 지원하지 않기 때문에, 상당히 커다란 상속 트리를 가지게 된다. 티오피젝트 클래스는 알티티아이(RTTI)를 사용할 수 있으며, 그 밖에 몇 가지 기본적인 특징을 가진다.[2]
- 하위형 호환형
오브젝트 파스칼은 비교적 형 검사가 엄격한 편이다. 이는 기본적으로 서로 다른 클래스의 객체들간의 형-호환성(type-compatibility)이 보장되지 않는다는 것이다. 이러한 규칙의 예외가 있는데, 특정 클래스를 상속한 클래스의 객체는 부모 클래스와 데이터형의 호환성이 인정된다. (역은 성립하지 않는다.),이러한 하위형 호환성은 다형성(polymorphism)과 레이트 바인딩(late binding)을 지원하는 데 중요한 역할을 한다. 오브젝트 파스칼은 모든 객체에 대해서 하위형 호환성을 지원한다. 이것이 가능한 이유는 객체 참조 모델을 사용하기 때문이다. 오브젝트 파스칼의 예를 들면, 모든 객체는 티오비젝트 클래스와 호환된다. 또 한 메소드를 디스패치할 때 정적, 동적 바인딩을 모두 지원한다. 정적 바인딩은 다형성을 지원하지 않으며, 컴파일 시에 동작하며 전통적인 함수 호출에서 사용되는 방식이다. 정적 메소드의 주소는 링커에 의해 코드 세그먼트에 직접 저장된다. 이에 비해 동적 바인딩 또는 가상 메소드는 다형성을 지원한다. 이를 위해 객체의 정확한 데이터형을 모르는 런타임에서 동작하게 된다. 오브젝트 파스칼은 가상 메모리 테이블(VMT)을 통해 가상 메소드의 주소를 저장한다. 각 클래스는 자신의 가상 메모리 테이블을 가지게 되며, 가상 메모리 테이블에 있는 함수 주소의 배열을 이용한다. 가상 메소드는 이 주소를 직접 이용하므로 동작하는 속도는 그렇게 느리지 않다. 오브젝트 파스칼은 명시적으로 가상으로 선언한 메소드만 다형성을 지원한다. 이는 하이브리드 언어라면 조상 언어의 호환성을 유지해야 하며, 성능상의 문제가 있다. 부모 클래스의 메소드를 새롭게 정의한 클래스가 있을 때, 일반적인 객체에 대하여 그 메소드를 호출할 때 적절한 클래스의 메소드가 호출되는 특징을 다형성이라고 한다. 이를 지원하려면 지원한 하위형 호환성이 매우 중요한 역할을 하게 된다. 컴파일러는 다형성을 지원하기 위해서 레이트 바인딩이라는 기법을 사용하게 되는데, 이것은 특정 함수를 호출하지 않고 런타임에서 객체가 실제로 어떤 클래스의 함수를 호출하게 될지를 알아낸 후에 호출된 함수를 결정하는 방식이다. 오브젝트는 파스칼의 경우에는 디폴트는 'early binding'이다. 그런데, 오브젝트 파스칼은 'virtual' 키워드로 지정하는 가상 함수 외에 'dynamic' 키워드로 지정하는 동적 함수가 지원된다. 'override' 키워드를 사용해야만 이들 가상 함수를 재정의 할 수 있다. 이러한 'override' 키워드의 의미는 지정한 메소드만 컴파일러가 다시 검사하게 되는 것이다. 이런 방법으로 비교적 효율적인 퍼포먼스를 유지할 수 있다. 또한, 오브젝트 파스칼에서는 가상 생성자(virtual constructor)를 정의할 수 있다. 오브젝트 파스칼은 가상 메소드 이외에 동적 메소드를 지원한다. 이 메소드는 원래 윈도의 메시지를 사용하기 위해 고안된 것이다. 즉, 수백 개가 넘는 윈도 메시지를 처리할 때에는 이들 각각에 대한 가상 메모리 테이블을 관리한다는 것은 메모리 공간의 낭비가 될 수 있음으로, 동적 메소드 테이블(Dynamic method table, DMT)을 통해 오버 라이드된 메시지 핸들러에 대한 주소만 관리함으로써 이러한 오버헤드를 줄일 수 있다. 그렇지만, 아무래도 수행능력이라는 측면에서는 다소 핸디캡을 가지고 있다고 본다.[2]
- 추상 메소드
비교적 복잡한 클래스 구조를 만들 때에는, 프로그래머가 다형성을 지원하는데 유리하도록 실제로 구현되지 않는 메소드를 선언할 필요가 있을 수 있다. 이러한 메소드를 추상 메소드(abstract method)라고 하며, 이러한 추상 메소드를 하나 이상 가지고 있는 클래스를 추상 클래스라고 한다. 오브젝트 파스칼은 추상 메소드를 가지고 있는 추상 클래스의 인스턴스를 생성하는 것이 가능하다. 그렇기 때문에, 프로그램이 추상 메소드를 호출할 가능성도 있는데 이렇게 되면 런타임 에러가 발생하게 된다.[2]
- 다중상속
일부의 객체지향 언어는 하나 이상의 기초 클래스를 상속 받을 수 있다. 이를 다중상속(multiple inheritance) 이라고 한다. 그에 비해 다른 언어에서는 오직 하나의 클래스만 상속받을 수 있지만, 옵션으로 다중 인터페이스나 순수한 추상 클래스(클래스의 순수한 추상 함수로만 이루어진 경우)들을 상속 받아 다중상속의 기능을 대치한다. 오브젝트 파스칼은 다중상속을 지원하지 않고, 다중 인터페이스를 지원한다. 이를 이용해서 다형성을 구현할 수 있으며, 이런 특징을 바탕으로 COM 모델에 적합한 언어환경이 지원된다. 오브젝트 파스칼은 자바보다 더욱 COM에 가까운 인터페이스 모델을 가지고 있다.[2]
- RTTI
런타임 타입 아이덴티피케이션/인폴메이션(Runtime Type Identification/information), 형 검사가 엄격한 객체지향 언어는 컴파일러가 이러한 형 검사를 해주어야 한다. 그러므로, 실행 중인 프로그램에는 클래스와 데이터 형에 대한 정보가 벼로 필요없다. 그러나, 어떤 경우네는 이러한 데이터 형에 대한 정보가 필요한 경우가 있는데, 이런 경우를 위해 각 언어들은 정도에 차이는 있지만 RTTI를 지원하고 있다. 오브젝트 파스칼은 가장 광범위한 RTTI 정보를 제공한다. 이를 이용해서 단순한 데이터형 검사와 'downcast'를 할 수 있으며 더 나아가서는 'published'로 선언된 요소들을 새로운 RTTI 정보로 등록할 수도 있다. 프로퍼티와 스트리밍 메커니즘(폼 파일 등의)과 오브젝트 인스펙터로 표현되는 델파이의 환경은 기본적으로 이런 RTTI가 있기에 가능한 것이다. 델파이 클래스의 기초 클래스인 티오피젝트 클래스에는 클래스네임(ClassName), 클래스타입(ClassType) 메소드가 있는데, ClassType 메소드를 사용해서 특정 객체의 클래스에 대한 참조 값을 돌려 받을 수 있다. 이 메소드를 통해서 반환되는 클래스 형은 티클래스(TClass)로 이 클래스는 티오비젝트의 클래스로 선언되어 있는데, 이는 이렇게 티클래스 형으로 반환된 클래스는 반드시 사용되기 전에 특정 클래스로 형 변환되어야 한다는 것을 의미한다.[2]
- 예외처리
예외처리란 프로그램의 에러 처리 부분을 보다 손쉽게 하기 위해, 언어에서 제공하는 표준 메커니즘을 말한다. 예외처리 방식은 언어들 마다 비슷하지만, 내부 동작에는 다소간의 차이가 존재한다. 오브젝트 파스칼은 raise, try, except 키워드를 사용한다. C++ 과의 차이점은 기본적으로 스택에 객체에 대한 메모리가 할당됭 있지 않기 때문에, 스택을 처리할 필요가 없다는 것이다. 또한, finally 키워드를 지원하며 델파이의 모든 예외 클래스는 Exception 클래스를 상속한다.[2]
- 그 밖의 특징
오브젝트 파스칼은 클래스 참조를 지원하기 때문에, 메소드 포인터를 아주 쉽게 사용할 수 있다. 이러한 메소드 포인터는 이벤트 모델의 기초가 되며, 이를 프로퍼티로 사용할 수 있다. 프로퍼티는 메소드가 데이터에 접근하는 방법을 숨겨주는 방법으로 사용되는데, 데이터를 직접 읽거나 쓸 수도 있고, 접근 메소드(access method)를 사용해서 데이터르 조작하는 방법도 가능하다. 데이터에 접근하는 방법을 바꾸더라도 코드를 호출하는 방법을 바꿀 필요가 없기 때문에, 재사용성이라는 측면에서 대단히 유용하다. 다르게 말하면, 다른 어떤 객체지향 언어보다도 강력한 캡슐화 방법을 지원하는 것이다. 또한, 델파이 4 에서는 그동안 지원하지 않았던 메소드 오버로딩과 파라미터의 디폴트 값도 지원하므로 보다 강력한 언어적 특성을 가지게 되었다.[2]
활용
서식
서식은 선언부와 구현부, 유닛의 참조, 형 정의, 함수의 모양, 루틴의 시작과 끝 등과 같이 언어의 전반적인 골격 구조를 말한다. 아래는 파스칼 유닛의 최소한의 서식이다.
- unit Unit1; --> 유닛의 종류와 이름이다. 이 부분과 interface 사이에는 주석을 제외하면 아무것도 있어서는 안된다.
- Interface --> 선언부이다. 자료형과 변수, 상수를 선언하는 용도로 사용한다. 다른 유닛에서 참조가 가능하다.
- Implementation --> 구현부이다. 자료형 선언 및 실제 문장을 작성하는 용도이다. 다른 유닛에 공개 하지 않는다.
- end. --> 유닛의 끝 부분임을 나타낸다. 델파이의 컴파일러는 이 라인 뒷부분은 모두 무시한다.
문장
문장은 실제로 실행 될 루틴을 말한다. 모든 문장은 문장의 끝을 알리기 위해 마지막에 세미콜론(;)을 붙이고 이것을 보통 한 라인이라고 부른다. 여러 코드라인을 작성할 경우 필요에 따라 이들을 하나로 묶기 위해 begin 과 end를 사용한다.문장은 선언부에는 사용될 수 없고 구현부에서만 사용될 수 있다.
식별자
프로그래머가 프로젝트에 사용되는 자료 형, 변수, 상수, 프로시저, 함수 등을 정의 할 때 사용하는 이름이다. 식별자의 명명 규칙은 다음과 같다.
- 영문 대소문자, 숫자, '_'만 사용할 수 있다.
- 첫 글자는 영문이나 '_'를 사용해야 한다.
- 길이 제한은 없으나 256자가 넘을 경우 256번째 부터의 문자는 무시된다.
- 대소문자를 구분하지 않는다.
예약어와 지시어
- 예약어 : 오브젝트 파스칼의 문법에서 사용하기 위해 미리 예약되어 있는 것으로 예약어와 같은 이름의 선언은 불가하다. and, downto, in, out, stringresource 등이 있다.
- 지시어 : 사용자가 정의한 식별자를 사용할 수 없는 위치에서 사용된다. absolute, dynamic, name, Public, safecall 등이 있다.
숫자와 문자열 표현법
- 숫자 : 소스 코드 상에서 숫자는 별도의 예약어 같은 것 없이 그냥 숫자를 그대로 사용하면 되고, 16진수의 경우에는 앞에 '$'를 붙여서 16진수임을 나타낸다. 실수인 경우는 소수점 이하의 값이 길어지면 e와 함께 자릿수를 표시한다.
- 문자열 : 문자열은 작은 따옴표(')로 표현한다.
자료형
- 숫자에 관련된 자료형 : 정수형과 실수형으로 나눌수있다. 정수형인 Integer와 Cardinal 이 외의 형들은 fundamental 타입이라고 하는데 이것들은 CPU, OS와 관계 없이 어느 시스템에서도 일정한 범위를 가지고 있다.
- 문자에 관련된 자료형 : 일반형과 기본형으로 나눌수있다. 일반 자료형은 8bit의 char 데이터형을 포함하며 기본 자료형은 AnsiChar와 WideChar를 포함한다. 일반형 Char는 기본형 AnsiChar와 동일한 표현범위를 가진다.
- 기타 자료형 : 논리형, 열거형, 부범위형, 집합형, Variant형, 배열, 레코드형 등이 있다.
변수와 연산자
- 변수 : 메모리 상에 마련되는 일정 공간이며 자료형에 따른 값, 데이터를 저장 할 수 있다.
- 연산자 : 데이터를 포함하고 있는 변수들에 대해 연산을 수행하기 위한 기호이다. 오브젝트 파스칼에서 가장 기본적인 연산자는 할당 연산자이다. ':=' 기호로 사용된다. C언어에서는 할당 연산자가 '='기호인데 오브젝트 파스칼에서는 '='기호가 단순히 Equal의 의미로 사용된다. 연산자는 크게 산술 연산자, 비교 연산자, 논리 연산자로 나눌수 있다.
포인터
포인터는 변수, 상수, 함수 등의 데이터가 위치하고 있는 메모리 주소의 주소값을 가리키는 자료형이다. 어떤 데이터의 주소 값을 가리킬 때는 @ 연산자를 사용한다. 델파이에서는 포인터는 Integer와 같은 정수형과는 다른 별도의 자료형이므로 포인터형과 정수형은 숫자라는 것은 같지만 사용 용도가 다르므로 그냥 호환되지는 않는다. 포인터가 가리키는 메모리의 값을 읽어올 때는 ^를 사용한다.
상수
상수는 프로그램 실행 중에 값이 변경되지 않는 값을 의미한다. 상수는 프로그램의 실행 중에 값이 변경되지 않는 것이 주요 목적이었지만, 조금 다른 목적을 갖는 상수도 있을 수 있다. 즉 초기값을 가진 변수의 개념으로 사용되는 것이 그것인데, 이런 상수를 형 정의된 상수(Typed constant)라고 부른다.
평가
오브젝트 파스칼은 언어는 특장점을 많이 가진 언어이다. 하지만 실제 세계에서 사용되는 개발환경을 좌우하지는 않는다. 실제로 중요한 것은 운영체제와 최근에 불어닥치는 인터넷 세계, 그리고 Win32API, 액티브 X 등의 모든 주변환경들과 이들의 관계, 개발자 들이 선택한 마켓 쉐어 등이라고 할 수 있다. 아무리 훌륭한 언어라도 실제로 사용되지 않는 경우는 부지기수이다. 오브젝트 파스칼의 경우 대단히 훌륭한 객체지향 언어이지만 대학에서나 학문적으로 사용될 뿐 실제 시장에서는 외면받고 있는 언어이다.[2]
각주
참고자료
- devWANI, 〈(PASCAL)오브젝트 파스칼이란...〉, 《티스토리》, 2008-12-23
- 델파이포럼 공식 홈페이지 - http://delphi.borlandforum.com/
같이 보기
이 문서는 로고가 필요합니다.