맨위로가기

클래스 (컴퓨터 프로그래밍)

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

클래스는 객체를 생성하기 위한 설계도로, 객체의 상태(데이터)와 동작(메서드)을 정의한다. 객체 지향 프로그래밍의 핵심 개념으로, 캡슐화, 상속, 다형성을 통해 코드의 재사용성과 유지보수성을 높인다. 클래스는 추상 클래스, 구체 클래스, 내부 클래스 등 다양한 종류가 있으며, 구성, 상속, 연관 관계를 통해 다른 클래스와 관계를 맺는다. 런타임에 클래스 정보에 접근하거나 조작할 수 있는 메커니즘을 제공하는 언어도 있다.

2. 클래스 설계의 기본 개념

클래스 설계에는 몇 가지 중요한 개념들이 있다. 객체는 각 멤버 변수의 유형과 각 멤버 함수(메서드)의 자료형을 인터페이스로 표현한다. 클래스는 이러한 인터페이스의 구현을 정의하며, 클래스를 인스턴스화하면 인터페이스를 통해 구현을 노출하는 객체가 생성된다.[2] 형식 이론 관점에서 보면, 클래스는 "구체적인" 자료 구조와 서브루틴 모음인 구현이고, 형식은 인터페이스이다. 서로 다른 클래스들이 동일한 (추상적인) 형식의 객체를 생성할 수 있다. 예를 들어, `Stack` 형식(인터페이스)은 `SmallStack`과 `ScalableStack`으로 구현될 수 있는데, 전자는 작지만 확장성이 떨어지고 후자는 확장성은 좋지만 작은 스택에는 오버헤드가 크다.[3]

2. 1. 캡슐화 (Encapsulation)

일반적으로 모든 프로그램은 기능을 제공하기 위해 데이터를 보유할 뿐만 아니라, 데이터에 대한 조작도 가능해야 한다. 단순히 여러 데이터를 묶는 수단으로는, C 언어의 구조체나 파스칼의 레코드형과 같은 형태로 기존의 절차 지향 프로그래밍 언어에서도 제공되었다. 한편, 클래스는 데이터뿐만 아니라 해당 데이터와 관련된 조작도 함께 묶어 관리하는 틀을 제공한다.

이처럼 관련된 변수나 조작 등을 클래스 소속으로 하나로 묶는 것을 클래스에 의한 정보의 캡슐화(encapsulation)라고 부른다. 적절한 캡슐화를 통해 데이터 구조나 알고리즘 등을 변경하더라도, 변경 부분은 캡슐화된 클래스 영역 내에서만 끝나며, 변경 부분이 클래스 외부의 관련 소스 코드 전체로 흩어지고 파급되는 것을 방지할 수 있다.

또한 접근 지정자를 통해 소속물에 대해 공개/비공개 정보의 구별을 두어, 클래스 외부에서 클래스 내부에 파괴적인 조작을 가하는 것을 방지하거나, 특정 기밀 데이터를 클래스 외부에서 볼 수 없도록 하는 등, 외부에 공개하는 정보에 제한을 둘 수 있다. 캡슐화한 위에 공개/비공개 정보의 구별을 더하는 것을 '''정보 은닉''' (information hiding)이라고 부른다[44][45]

2. 2. 상속 (Inheritance)

'''상속''' (inheritance) 또는 '''확장''' (extension)은 기존 클래스를 기반으로 새로운 클래스를 만드는 것을 말한다. 이는 단순한 클래스를 바탕으로 더 복잡한 클래스를 만들고, 클래스 간의 계층을 구성하는 데 목적이 있다.[46][47] 상속의 기반이 되는 클래스를 '''부모 클래스''', '''기본 클래스''', '''기저 클래스''' 또는 슈퍼클래스라고 부르며, 상속을 통해 만들어진 클래스는 '''자식 클래스''', '''파생 클래스''' 또는 서브클래스라고 한다. 파생 클래스의 인스턴스는 기본 클래스의 인스턴스로도 취급될 수 있다 (리스코프 치환 원칙).

개념적으로 슈퍼클래스는 서브클래스의 상위 집합이다. 예를 들어, `GraphicObject`는 `Rectangle`과 `Ellipse`의 슈퍼클래스가 될 수 있으며, `Square`는 `Rectangle`의 서브클래스가 될 수 있다. 이는 집합론에서의 부분 집합 관계와 같다. 즉, 모든 사각형은 직사각형이지만 모든 직사각형이 사각형인 것은 아니다.

흔히 ''부분'' 관계를 서브클래스로 오해하는 경우가 많다. 예를 들어, 자동차와 트럭은 모두 차량의 종류이므로 차량 클래스의 서브클래스로 모델링하는 것이 적절하다. 그러나 자동차의 부품(엔진, 차체 등)을 자동차의 서브클래스로 모델링하는 것은 적절하지 않다. 객체 지향 모델링에서 이러한 관계는 일반적으로 객체 속성으로 모델링된다.

UML과 같은 객체 모델링 언어는 "부분" 관계 등 다양한 관계의 측면을 모델링하는 기능을 포함한다.

상속은 개방/폐쇄 원칙에 기초하여, 단순한 기본 클래스로부터 더 복잡한 파생 클래스를 구성하는 기구이며, 코드의 재사용과 확장을 용이하게 한다.

클래스 계층 구조를 런타임에 수정할 수 있는지 여부도 중요한 문제이다. Flavors, CLOS, Smalltalk와 같은 언어는 메타 객체 프로토콜의 일부로 이 기능을 지원한다. 반면 Java, C++와 같이 강력한 형식 지정에 중점을 둔 언어는 런타임에 클래스 계층 구조를 수정할 수 없다. 시맨틱 웹 객체는 런타임에 클래스를 변경할 수 있다.

많은 클래스 기반 언어가 상속을 지원하지만, 상속이 클래스의 본질적인 측면은 아니다. 객체 기반 언어 (예: 클래식 비주얼 베이직)는 클래스를 지원하지만 상속을 지원하지 않는다.

UML에서는 상속을 '''일반화''' (generalization영어)라고 부른다. 일반화는 슈퍼클래스에 의한 추상화이며, 대립어인 '''특수화''' (specialization영어)는 서브클래스에 의한 구체화를 의미한다.

객체 지향을 효율적으로 사용하기 위해서는 상속뿐만 아니라 집약 (aggregation영어), 위임 (delegation영어)도 이해해야 한다.

C++ 등의 언어에서는 기존 클래스를 상속한 클래스를 만듦으로써 새로운 메서드를 추가할 수 있다.

2. 2. 1. 다중 상속 (Multiple Inheritance)

Flavors나 CLOS와 같은 일부 시스템은 런타임에 둘 이상의 부모를 가질 수 있는 기능을 제공하지만, 이는 객체 지향 커뮤니티의 많은 사람들이 객체 클래스를 사용하는 목표와 상반된다고 생각하는 복잡성을 유발한다. 하나 이상의 슈퍼클래스를 다룰 때 어떤 클래스가 메시지를 처리할 책임이 있는지 이해하는 것은 복잡해질 수 있다. 부주의하게 사용하면 이 기능은 클래스가 피하도록 설계된 동일한 시스템 복잡성 및 모호성을 유발할 수 있다.[12]

Smalltalk 및 Java와 같은 대부분의 현대 객체 지향 언어는 런타임에 단일 상속을 요구한다. 이러한 언어의 경우, 다중 상속은 모델링에는 유용할 수 있지만 구현에는 유용하지 않을 수 있다.

그러나 시맨틱 웹 응용 프로그램 객체는 여러 개의 슈퍼클래스를 가지고 있다. 인터넷의 변동성은 이러한 수준의 유연성을 요구하며, 웹 온톨로지 언어 (OWL)과 같은 기술 표준은 이를 지원하도록 설계되었다.

복수의 기본 클래스를 상속하여 하나의 새로운 클래스를 파생시키는 것을 다중 상속이라고 부른다. 다중 상속을 통해 기반이 된 모든 클래스의 소속물은 합쳐져 하나가 되고, 모든 동작이 조합된 새로운 하나의 클래스가 구성된다. 단, 구현의 다중 상속은 두 개의 기본 클래스의 동명 메서드의 오버라이드에 의한 충돌을 비롯한 몇 가지 문제점 (다이아몬드 상속 문제 등)이 지적되고 있다. 따라서 구현의 상속은 통상, 하나의 클래스를 기반으로 그 확장을 수행하는 단일 상속을 사용한다. C++는 다중 상속을 허용하며, 다중 상속에 얽힌 문제의 해결 수단을 가상 상속에 의해 제공하고 있지만, 다른 많은 언어, 예를 들어 Java, C#, D 언어에서는 구현의 다중 상속은 지원되지 않고, 인터페이스의 복수 구현에 의한 타입의 다중 상속만 지원되고 있다. 단, Java 8 이후는 인터페이스의 기본 구현을 통해, 구현의 다중 상속도 제한적으로 지원하게 되었다. 또한, Simula 67은 다중 상속도 인터페이스도 지원하지 않았다.[48]

2. 3. 다형성 (Polymorphism)

클래스를 상속할 때, 슈퍼클래스의 동작을 서브클래스의 동작으로 덮어쓰는(바꾸는) 것을 '''오버라이드'''라고 한다. 어떤 서브클래스의 인스턴스가 오버라이드된 동작을 가질 경우, 인스턴스의 구체적인 내용(클래스)을 몰라도, 인스턴스에 해당 동작을 실행하도록 지시하면, 겉보기에는 슈퍼클래스와 같으면서(즉, 인터페이스가 같으면서), 인스턴스의 실제 클래스에 따라 실행되는 동작(처리 내용)을 변경할 수 있다. 이처럼 겉보기는 같지만 동작이 바뀌는 것을 '''다형성'''이라고 한다.

2. 4. 추상화 (Abstraction)

클래스는 자료형을 인터페이스로 표현하며, 인터페이스의 구현을 정의한다. 클래스를 인스턴스화하면 인터페이스를 통해 구현을 노출하는 객체가 생성된다.[2] 형식 이론의 측면에서 클래스는 구현, 즉 "구체적인" 자료 구조와 서브루틴 모음이고, 형식은 인터페이스이다. 서로 다른 클래스는 동일한 형식의 객체를 생성할 수 있다. 예를 들어, `Stack` 형식(인터페이스)은 `SmallStack`과 `ScalableStack`으로 구현될 수 있다.[3]

클래스 또는 인스턴스의 동작은 메서드를 사용하여 정의한다. 메서드는 객체 또는 클래스에서 작동할 수 있는 서브루틴이다. 이러한 연산은 객체의 상태를 변경하거나 단순히 객체에 접근하는 방법을 제공할 수 있다.[4]

모든 클래스는 구조와 동작을 제공함으로써 인터페이스를 ''구현''한다. 구조는 데이터와 상태로 구성되며, 동작은 메서드 구현 방식을 지정하는 코드로 구성된다.[5] 많은 프로그래밍 언어에서 클래스 선언이 인터페이스를 정의하고 구현하기 때문에 인터페이스와 구현 사이의 구분이 모호하다. 하지만 일부 언어는 인터페이스와 구현을 분리하는 기능을 제공한다. 예를 들어, 추상 클래스는 구현을 제공하지 않고 인터페이스를 정의할 수 있다.

클래스 상속을 지원하는 언어는 클래스가 파생된 클래스로부터 인터페이스를 상속받을 수도 있다. 예를 들어, "클래스 A"가 "클래스 B"에서 상속받고 "클래스 B"가 "인터페이스 B"를 구현하는 경우, "클래스 A"는 "인터페이스 B"에서 제공하는 기능(상수 및 메서드 선언)도 상속받는다.

접근 지정자를 지원하는 언어에서 클래스의 인터페이스는 메서드와 속성(암시적 getter 및 setter 메서드를 통해)을 포함하는 클래스의 공개 멤버 집합으로 간주된다.

객체 지향 프로그래밍 방법론은 클래스의 모든 인터페이스의 연산이 서로 독립적이어야 한다고 규정한다. 인터페이스는 클라이언트가 특정 순서로 한 인터페이스의 연산을 호출하도록 요구하지 않는다.[6]

; 클래스 인터페이스 예시

TV 앞면의 버튼은 사용자와 TV 내부 전기 배선 사이의 인터페이스이다. "전원" 버튼을 눌러 TV를 켜고 끈다. 이 예에서 특정 TV가 인스턴스이고, 각 메서드는 버튼으로 표현되며, 모든 버튼을 함께 구성하여 인터페이스를 구성한다(같은 모델의 다른 TV는 동일한 인터페이스를 가짐). 인터페이스는 메서드의 구현 없이 관련 메서드 그룹의 사양이다.

TV는 크기 및 컬러 지원 여부와 같은 속성들을 가지며, 이는 함께 구조를 구성한다. 클래스는 속성(구조)과 버튼(인터페이스)을 포함하여 TV의 전체 설명을 나타낸다.

제조된 TV의 총 개수를 구하는 것은 TV 클래스의 ''정적 메서드''일 수 있다. 이 메서드는 클래스와 연결되어 있지만 클래스의 각 인스턴스 영역 밖에 있다.

3. 클래스의 종류

객체는 각 멤버 변수의 유형과 각 멤버 함수(메서드)의 자료형을 인터페이스로 표현한다. 클래스는 인터페이스의 구현을 정의하며, 클래스를 인스턴스화하면 인터페이스를 통해 구현을 노출하는 객체가 생성된다.[17] 형식 이론 측면에서 클래스는 구현(구체적인 자료 구조와 서브루틴 모음)이고, 형식은 인터페이스이다. 서로 다른 (구체적인) 클래스는 동일한 (추상적인) 형식의 객체를 생성할 수 있다(형식 시스템에 따라 다름). 예를 들어, `Stack` 형식(인터페이스)은 작은 스택에 빠르지만 확장성이 좋지 않은 `SmallStack`과 확장성은 좋지만 작은 스택에 오버헤드가 큰 `ScalableStack`으로 구현될 수 있다.

3. 1. 추상 클래스 (Abstract Class)

상속을 지원하는 언어에서, 추상 클래스(또는 추상 기본 클래스, ABC)는 직접 인스턴스화할 수 없는 클래스이다. 반대로, 구체 클래스는 직접 인스턴스화할 수 있는 클래스이다. 추상 클래스의 인스턴스화는 구체 하위 클래스를 통해서만 간접적으로 발생할 수 있다.

추상 클래스는 명시적으로 추상으로 지정되거나, 단순히 추상 메서드(또는 가상 메서드)를 지정할 수 있다. 추상 클래스는 일부 메서드의 구현을 제공할 수 있으며, 추상 클래스의 직계 또는 간접 후손에 의해 구현될 시그니처를 통해 가상 메서드를 지정할 수도 있다. 추상 클래스에서 파생된 클래스를 인스턴스화하기 전에, 해당 부모 클래스의 모든 추상 메서드는 파생 체인의 일부 클래스에 의해 구현되어야 한다.[16]

대부분의 객체 지향 프로그래밍 언어는 프로그래머가 어떤 클래스를 추상으로 간주할지 지정할 수 있으며, 이러한 클래스를 인스턴스화하는 것을 허용하지 않는다. 예를 들어, 자바, C 샤프 및 PHP에서는 ''abstract'' 키워드를 사용한다.[17][18] C++에서 추상 클래스는 해당 언어의 적절한 구문(C++ 용어에서 순수 가상 함수)으로 제공되는 최소 하나의 추상 메서드를 갖는 클래스이다.[16]

순수 가상 메서드로만 구성된 클래스는 C++에서 순수 추상 기본 클래스(또는 순수 ABC)라고 불리며, 해당 언어 사용자는 이를 인터페이스라고도 부른다.[8] 다른 언어, 특히 자바와 C#은 언어 내 키워드를 통해 인터페이스라고 하는 추상 클래스의 변형을 지원한다. 이러한 언어에서는 다중 상속이 허용되지 않지만, 클래스는 여러 인터페이스를 구현할 수 있다. 이러한 클래스는 추상적으로 공개적으로 접근 가능한 메서드만 포함할 수 있다.[14][19][20]

3. 2. 구체 클래스 (Concrete Class)

상속을 지원하는 언어에서, 추상 클래스(abstract class) 또는 추상 기본 클래스(ABC, abstract base class)는 직접 인스턴스화할 수 없는 클래스이다. 반대로, 구체 클래스(concrete class)는 직접 인스턴스화할 수 있는 클래스이다. 추상 클래스의 인스턴스화는 구체적인 하위 클래스를 통해서만 간접적으로 발생할 수 있다.

추상 클래스는 명시적으로 추상으로 지정되거나, 단순히 추상 메서드(또는 가상 메서드)를 지정할 수 있다. 추상 클래스는 일부 메서드의 구현을 제공할 수 있으며, 추상 클래스의 직계 또는 간접 후손에 의해 구현될 시그니처를 통해 가상 메서드를 지정할 수도 있다. 추상 클래스에서 파생된 클래스를 인스턴스화하기 전에, 해당 부모 클래스의 모든 추상 메서드는 파생 체인의 일부 클래스에 의해 구현되어야 한다.[16]

대부분의 객체 지향 프로그래밍 언어는 프로그래머가 어떤 클래스를 추상으로 간주할지 지정할 수 있으며, 이러한 클래스를 인스턴스화하는 것을 허용하지 않는다. 예를 들어, 자바, C 샤프 및 PHP에서는 `abstract` 키워드를 사용한다.[17][18] C++에서 추상 클래스는 해당 언어의 적절한 구문(C++ 용어에서 순수 가상 함수)으로 제공되는 최소 하나의 추상 메서드를 갖는 클래스이다.[16]

순수 가상 메서드로만 구성된 클래스는 C++에서 순수 추상 기본 클래스(또는 순수 ABC)라고 불리며, 해당 언어 사용자는 이를 인터페이스라고도 부른다.[8] 다른 언어, 특히 자바와 C#은 언어 내 키워드를 통해 인터페이스라고 하는 추상 클래스의 변형을 지원한다. 이러한 언어에서는 다중 상속이 허용되지 않지만, 클래스는 여러 인터페이스를 구현할 수 있다. 이러한 클래스는 추상적으로 공개적으로 접근 가능한 메서드만 포함할 수 있다.[14][19][20]

3. 3. 내부 클래스 (Inner Class)

일부 언어에서 클래스는 전역 범위를 제외한 다른 범위 내에서 선언될 수 있다.

'''내부 클래스'''는 다른 클래스 내에 정의된 클래스이다.[21][22] 내부 클래스와 이를 포함하는 클래스 간의 관계는 또 다른 유형의 클래스 연결로 간주될 수도 있다. 내부 클래스는 일반적으로 둘러싸는 클래스의 인스턴스와 연결되지 않으며, 둘러싸는 클래스와 함께 인스턴스화되지 않는다. 언어에 따라 둘러싸는 클래스 외부에서 해당 클래스를 참조할 수 있거나 없을 수도 있다. 관련 개념은 '''내부 유형'''으로, '''내부 데이터 유형''' 또는 '''중첩 유형'''이라고도 하며, 내부 클래스 개념의 일반화이다. C++(C++)는 내부 클래스와 내부 유형(''typedef'' 선언을 통해)을 모두 지원하는 언어의 예이다.

'''지역 클래스'''는 프로시저 또는 함수 내에 정의된 클래스이다. 이러한 구조는 클래스 이름에 대한 참조를 클래스가 선언된 범위 내로 제한한다. 언어의 의미 규칙에 따라 지역 클래스는 비지역 클래스에 비해 추가적인 제약이 있을 수 있다. 한 가지 일반적인 제약은 지역 클래스 메서드가 둘러싸는 함수의 지역 변수에 접근하는 것을 허용하지 않는 것이다. 예를 들어, C++에서 지역 클래스는 둘러싸는 함수 내에 선언된 정적 변수를 참조할 수 있지만, 함수의 자동 변수에는 접근할 수 없다.[23]

3. 4. 지역 클래스 (Local Class)

일부 언어에서 클래스는 전역 범위를 제외한 다른 범위 내에서 선언될 수 있다. 이러한 클래스에는 다양한 유형이 있다.

''지역 클래스''는 프로시저 또는 함수 내에 정의된 클래스이다. 이러한 구조는 클래스 이름에 대한 참조를 클래스가 선언된 범위 내로 제한한다. 언어의 의미 규칙에 따라 지역 클래스는 비지역 클래스에 비해 추가적인 제약이 있을 수 있다. 한 가지 일반적인 제약은 지역 클래스 메서드가 둘러싸는 함수의 지역 변수에 접근하는 것을 허용하지 않는 것이다. 예를 들어, C++(C++)에서 지역 클래스는 둘러싸는 함수 내에 선언된 정적 변수를 참조할 수 있지만, 함수의 자동 변수에는 접근할 수 없다.[23]

3. 5. 봉인 클래스 (Sealed Class)

C#에서는 `sealed` 키워드를, 자바나 PHP에서는 `final` 키워드를 사용하여 봉인 클래스로 선언한다.[27][28][29] 예를 들어, 자바의 String 클래스는 `final`로 표시되어 있다.[30]

봉인 클래스는 서브클래스로 만들 수 없다. 이는 사용하기 위해 파생되어야 하는 추상 클래스와 정반대이다. 봉인 클래스는 암묵적으로 구체적이다.

봉인 클래스는 컴파일러가 서브클래스로 만들 수 있는 클래스에서는 사용할 수 없는 최적화를 수행할 수 있게 해준다.[31]

3. 6. 열린 클래스 (Open Class)

열린 클래스는 변경될 수 있다. 일반적으로, 실행 프로그램은 고객에 의해 변경될 수 없다. 개발자는 종종 일부 클래스를 변경할 수 있지만, 일반적으로 표준 또는 내장 클래스는 변경할 수 없다. 루비에서는 모든 클래스가 열려 있다. 파이썬에서는 런타임에 클래스를 생성할 수 있으며, 이후 모든 클래스를 수정할 수 있다.[32] Objective-C 카테고리는 프로그래머가 해당 클래스를 다시 컴파일하거나 소스 코드에 접근할 필요 없이 기존 클래스에 메서드를 추가할 수 있도록 허용한다.

3. 7. 부분 클래스 (Partial Class)

이 기능을 지원하는 언어에서 '''부분 클래스'''는 정의가 단일 소스 코드 파일 내에서 또는 여러 파일에 걸쳐 여러 조각으로 분할될 수 있는 클래스이다.[33] 이 조각들은 컴파일 시간에 병합되어 컴파일러의 출력물이 부분 클래스가 아닌 경우와 동일하게 된다.

부분 클래스가 도입된 주요 동기는 자동 프로그래밍과 같은 코드 생성기 구현을 용이하게 하기 위함이다.[33] 개발자가 작성한 코드 내에 생성된 코드가 인터리빙될 때 생성된 코드를 관리할 수 있는 코드 생성기를 개발하는 것은 어려운 과제이거나 타협이 필요하다. 부분 클래스를 사용하면 코드 생성기가 파일 내에서 별도의 파일이나 거친 입자의 부분 클래스를 처리할 수 있으므로 광범위한 파싱을 통해 생성된 코드를 복잡하게 삽입할 필요가 없어 컴파일러 효율성을 높이고 개발자 코드를 손상시킬 위험을 제거할 수 있다. 부분 클래스의 간단한 구현에서 컴파일러는 부분 클래스의 모든 부분을 "통합"하는 사전 컴파일 단계를 수행할 수 있다. 그러면 평소대로 컴파일을 진행할 수 있다.

부분 클래스 기능의 다른 장점과 효과는 다음과 같다.

  • 클래스의 인터페이스와 구현 코드를 고유한 방식으로 분리할 수 있다.
  • 소스 코드 편집기 내에서 대규모 클래스를 쉽게 탐색할 수 있다.
  • 관심사 분리관점 지향 프로그래밍과 유사한 방식으로 수행할 수 있지만 추가 도구를 사용하지 않는다.
  • 여러 개발자가 나중에 개별 코드를 하나의 파일로 병합할 필요 없이 단일 클래스에서 동시에 작업할 수 있다.


부분 클래스는 스몰토크에서 ''클래스 확장''이라는 이름으로 상당 기간 존재해 왔다. .NET 프레임워크 2가 출시되면서 마이크로소프트(Microsoft)는 C# 2.0 및 Visual Basic 2005에서 모두 지원되는 부분 클래스를 도입했다. WinRT 또한 부분 클래스를 지원한다.

4. 클래스 간의 관계

클래스는 서로 관계를 맺을 수 있으며, 이러한 관계는 프로그램의 구조와 동작 방식을 결정하는 데 중요한 역할을 한다. 클래스 간의 주요 관계는 다음과 같다.


  • 구성 (Composition): 한 클래스가 다른 클래스를 포함하는 관계이다. 예를 들어, '자동차' 클래스는 '엔진', '바퀴', '차체' 등의 클래스로 구성될 수 있다. 이 관계는 "has-a"(~을 가지고 있다) 관계로 표현된다. 자동차는 엔진을 ''가지고 있다''. 구성 관계에서 포함하는 클래스(자동차)의 인스턴스가 소멸되면 포함된 클래스(엔진)의 인스턴스도 함께 소멸되는 경우가 많다.[1]
  • 상속 (Inheritance): 한 클래스(자식 클래스)가 다른 클래스(부모 클래스)의 특성(속성 및 메서드)을 물려받는 관계이다. 예를 들어, '사각형' 클래스는 '도형' 클래스의 속성과 메서드를 상속받을 수 있다. 이 관계는 "is-a"(~이다) 관계로 표현된다. 정사각형은 직사각형 ''이다''. 상속을 통해 코드를 재사용하고 클래스 간의 계층 구조를 만들 수 있다. 상속은 개방/폐쇄 원칙에 기반하며, 코드 재사용과 확장을 용이하게 한다.
  • 연관 (Association): 두 클래스가 서로 협력하는 관계이다. 예를 들어, '학생' 클래스와 '강좌' 클래스는 서로 연관 관계를 가질 수 있다. 학생은 강좌를 수강하고, 강좌에는 여러 학생이 등록될 수 있다. 연관 관계는 방향성을 가질 수 있으며, 각 클래스의 역할과 참여하는 인스턴스 수를 지정할 수 있다.[15]

4. 1. 구성 (Composition)

클래스는 다른 클래스로 구성될 수 있으며, 이를 통해 포함하는 클래스와 내장된 클래스 간의 구성 관계를 설정한다. 클래스 간의 구성 관계는 일반적으로 'has-a' 관계라고도 한다.[1] 예를 들어, "자동차" 클래스는 "엔진" 클래스로 구성되고 포함될 수 있다. 따라서 자동차는 엔진을 ''가지고 있다''. 구성의 한 측면은 포함이며, 이는 구성 요소를 가지고 있는 인스턴스에 의한 구성 요소 인스턴스의 묶음을 의미한다. 포함하는 객체가 값으로 구성 요소 인스턴스를 포함하는 경우, 구성 요소와 포함하는 객체는 유사한 객체 수명을 갖는다. 구성 요소가 참조로 포함되는 경우, 유사한 수명을 갖지 않을 수 있다.[2] 예를 들어, Objective-C 2.0에서:

이 `Car` 클래스는 `NSString` (문자열 객체), `Engine`, 및 `NSArray` (배열 객체)의 인스턴스를 ''가지고 있다''.

4. 2. 상속 (Inheritance)

'''상속'''은 기존 클래스를 기반으로 새로운 클래스를 만드는 방법이다. 개념적으로 슈퍼클래스(상위 클래스)는 서브클래스(하위 클래스)의 상위 집합이다. 예를 들어, `GraphicObject`는 `Rectangle`(사각형)과 `Ellipse`(타원)의 슈퍼클래스가 될 수 있으며, `Square`(정사각형)는 `Rectangle`의 서브클래스가 될 수 있다. 이는 집합론에서 부분 집합 관계와 같다. 즉, 모든 정사각형은 직사각형이지만 모든 직사각형이 정사각형은 아니다.

일반적인 개념적 오류는 ''부분'' 관계를 서브클래스로 오해하는 것이다. 예를 들어, 자동차와 트럭은 모두 차량의 종류이므로 차량 클래스의 서브클래스로 모델링하는 것이 적절하다. 그러나 자동차의 부품을 서브클래스 관계로 모델링하는 것은 오류이다. 자동차는 엔진과 차체로 구성되지만, 엔진이나 차체를 자동차의 서브클래스로 모델링하는 것은 적절하지 않다.

객체 지향 모델링에서 이러한 종류의 관계는 일반적으로 객체 속성으로 모델링된다. 이 예에서 `Car` 클래스는 `parts`라는 속성을 가지며, `parts`는 `Body`, `Engine`, `Tires` 등의 인스턴스와 같은 객체의 컬렉션을 보유하도록 형식화된다.

UML과 같은 객체 모델링 언어는 "부분" 및 기타 종류의 관계의 다양한 측면을 모델링하는 기능을 포함한다. 즉, 객체의 기수, 입력 및 출력 값에 대한 제약 조건 등의 데이터를 포함한다. 이 정보는 개발자 도구에서 객체에 대한 기본 데이터 정의 외에도 get 및 set 메서드에 대한 오류 검사와 같은 추가 코드를 생성하는 데 사용될 수 있다.[11]

객체 클래스 시스템을 모델링하고 구현할 때 중요한 질문 중 하나는 클래스가 하나 이상의 슈퍼클래스를 가질 수 있는지 여부이다. 실제 집합의 실제 세계에서는 둘 이상의 다른 집합과 교차하지 않는 집합을 찾기는 드물다. 그러나 Flavors와 CLOS와 같은 일부 시스템은 런타임에 둘 이상의 부모를 가질 수 있는 기능을 제공하지만, 그렇게 하는 것은 객체 지향 커뮤니티의 많은 사람들이 애초에 객체 클래스를 사용하는 목표와 상반된다고 생각하는 복잡성을 유발한다. 하나 이상의 슈퍼클래스를 다룰 때 어떤 클래스가 메시지를 처리할 책임이 있는지 이해하는 것은 복잡해질 수 있다. 부주의하게 사용하면 이 기능은 클래스가 피하도록 설계된 동일한 시스템 복잡성 및 모호성을 유발할 수 있다.[12]

Smalltalk 및 Java와 같은 대부분의 현대 객체 지향 언어는 런타임에 단일 상속을 요구한다. 이러한 언어의 경우, 다중 상속은 모델링에는 유용할 수 있지만 구현에는 유용하지 않을 수 있다.

그러나 시맨틱 웹 응용 프로그램 객체는 여러 개의 슈퍼클래스를 가진다. 인터넷의 변동성은 이러한 수준의 유연성을 요구하며, 웹 온톨로지 언어 (OWL)과 같은 기술 표준은 이를 지원하도록 설계되었다.

유사한 문제는 클래스 계층 구조를 런타임에 수정할 수 있는지 여부이다. Flavors, CLOS 및 Smalltalk와 같은 언어는 모두 해당 메타 객체 프로토콜의 일부로 이 기능을 지원한다. 클래스는 그 자체가 일급 객체이므로, 적절한 메시지를 보내서 구조를 동적으로 변경할 수 있다. Java 및 C++와 같이 강력한 형식 지정에 더 중점을 둔 다른 언어는 런타임에 클래스 계층 구조를 수정할 수 없다. 시맨틱 웹 객체는 런타임에 클래스를 변경할 수 있는 기능을 가진다. 그 이유는 다중 슈퍼클래스를 허용하는 것과 유사하며, 인터넷은 너무나 역동적이고 유연해서 계층 구조에 대한 동적 변경이 이러한 변동성을 관리하는 데 필요하다는 것이다.[13]

많은 클래스 기반 언어가 상속을 지원하지만, 상속은 클래스의 본질적인 측면은 아니다. 객체 기반 언어 (예: 클래식 비주얼 베이직)는 클래스를 지원하지만 상속을 지원하지 않는다.

클래스는 하나 이상의 기존 클래스에서 ''파생''될 수 있으며, 이로써 파생된 클래스(''기본 클래스'', ''부모 클래스'' 또는 ''상위 클래스'')와 파생 클래스(''자식 클래스'' 또는 ''하위 클래스'') 간의 계층적 관계가 설정된다. 파생 클래스와 파생된 클래스의 관계는 일반적으로 ''~이다 관계''라고 알려져 있다. 예를 들어, 'Button(버튼)' 클래스는 'Control(컨트롤)' 클래스에서 파생될 수 있다. 따라서, 버튼은 컨트롤 ''이다''. 부모 클래스의 구조적 및 행동적 멤버는 자식 클래스에 ''상속''된다. 파생 클래스는 ''상속''된 멤버 외에 추가적인 구조적 멤버(데이터 필드)와 행동적 멤버(메서드)를 정의할 수 있으며, 따라서 상위 클래스의 ''특수화''이다. 또한, 파생 클래스는 언어에서 허용하는 경우 상속된 메서드를 재정의할 수 있다.

모든 언어가 다중 상속을 지원하는 것은 아니다. 예를 들어, 자바(Java)는 클래스가 여러 인터페이스를 구현할 수 있지만 하나의 클래스에서만 상속받을 수 있다.[14] 다중 상속이 허용되는 경우 계층 구조는 방향 비순환 그래프 (줄여서 DAG)이고, 그렇지 않은 경우에는 트리가 된다. 계층 구조는 클래스를 노드로, 상속 관계를 링크로 갖는다. 동일한 레벨의 클래스는 다른 레벨의 클래스보다 연관될 가능성이 더 높다. 이 계층 구조의 레벨을 레이어 또는 추상화 레벨이라고 한다.

Objective-C 2.0 코드 예시 (iPhone SDK):

```objc

@interface UIResponder : NSObject //...

@interface UIView : UIResponder //...

@interface UIScrollView : UIView //...

@interface UITableView : UIScrollView //...

```

이 예에서 UITableView는 UIScrollView이고, UIScrollView는 UIView이며, UIView는 UIResponder이고, UIResponder는 NSObject ''이다''.

상속은 '''확장''' (extension)이라고도 한다. 기존 클래스를 기반으로 새로운 클래스를 구성한다. 그 목적은 단순한 클래스를 기반으로 더 복잡한 클래스를 구성하는 것이다. 또한, 복잡한 클래스는 이를 정의하는 단순한 클래스에 종속된다는 의미에서 클래스에 계층을 부여할 수 있게 된다.[46][47] 상속의 기반이 된 클래스를 '''부모 클래스''', '''기본 클래스''', '''기저 클래스''' 또는 '''슈퍼클래스''' 등으로 부르고, 상속되어 만들어진 클래스를 '''자식 클래스''', '''파생 클래스''' 또는 '''서브클래스''' 등으로 부른다. 파생 클래스의 인스턴스는 또한 기본 클래스의 인스턴스로서 취급될 수 있다 (리스코프 치환 원칙). 상속을 통해 다형성을 실현할 수 있게 된다.

UML에서는 상속을 '''일반화''' (generalization)라고 부른다. 일반화는 슈퍼클래스에 의한 추상화이며, 대립어인 '''특수화''' (specialization)는 서브클래스에 의한 구체화를 의미한다.

객체 지향을 효율적으로 사용하기 위해서는 상속뿐만 아니라 집약 (aggregation), 위임 (delegation)을 이해할 필요가 있다.

상속은 개방/폐쇄 원칙에 기초하여, 단순한 기본 클래스로부터 더 복잡한 파생 클래스를 구성하는 기구이며, 코드의 재사용과 확장을 용이하게 한다. 반대로 복잡한 클래스의 소속물 중 일부를 제외하고 단순한 클래스를 구성하려고 하면, 코드의 재사용과 확장을 저해하게 된다.

처음부터 다수의 소속물을 캡슐화하거나, 기본 클래스로부터 상속을 하더라도 다수의 소속물을 추가하여 극도로 특수화된 클래스를 처음부터 생성해 버리면, 도중에 그보다 약간 일반적인 클래스가 필요하게 되어도 대체할 수 없게 된다.

복수의 기본 클래스를 상속하여 하나의 새로운 클래스를 파생시키는 것을 다중 상속 (multiple inheritance)이라고 부른다. 다중 상속을 통해 기반이 된 모든 클래스의 소속물은 합쳐져 하나가 되고, 모든 동작이 조합된 새로운 하나의 클래스가 구성된다. 단, 구현의 다중 상속은 두 개의 기본 클래스의 동명 메서드의 오버라이드에 의한 컨플릭트를 비롯한 몇 가지 문제점 (다이아몬드 상속 문제 등)이 지적되고 있다. 따라서 구현의 상속은 통상, 하나의 클래스를 기반으로 그 확장을 수행하는 단일 상속을 사용한다. C++는 다중 상속을 허용하며, 다중 상속에 얽힌 문제의 해결 수단을 가상 상속에 의해 제공하고 있지만, 다른 많은 언어, 예를 들어 Java, C#, D 언어에서는 구현의 다중 상속은 지원되지 않고, 인터페이스의 복수 구현에 의한 타입의 다중 상속만 지원되고 있다. 단, Java 8 이후는 인터페이스의 디폴트 구현을 통해, 구현의 다중 상속도 제한적으로 지원하게 되었다. Simula 67은 다중 상속도 인터페이스도 지원하지 않았다.[48]

C++ 등의 언어에서는, 기존의 클래스를 상속한 클래스를 만듦으로써 새로운 메서드의 생성 (추가)이 가능하게 된다.

4. 3. 연관 (Association)

객체 지향 분석 및 설계와 통합 모델링 언어(UML)에서 두 클래스 간의 연관 관계는 클래스 또는 해당 인스턴스 간의 협업을 나타낸다. 연관 관계는 방향성을 가지며, 예를 들어 두 클래스 간의 양방향 연관 관계는 두 클래스 모두 관계를 인지하고 있음을 나타낸다.[15] 연관 관계는 이름 또는 목적에 따라 레이블이 지정될 수 있다.

연관 역할은 연관 관계의 끝에 주어지며 해당 클래스의 역할을 설명한다. 예를 들어 "구독자" 역할은 "Person" 클래스의 인스턴스가 "Magazine" 클래스와의 "구독" 연관 관계에 참여하는 방식을 설명한다. 또한 "Magazine"은 동일한 연관 관계에서 "구독된 잡지" 역할을 갖는다. 연관 역할 다중성은 연관 관계의 다른 클래스의 각 인스턴스에 해당하는 인스턴스 수를 설명한다. 일반적인 다중성은 "0..1", "1..1", "1..*" 및 "0..*"이며, 여기서 "*"는 임의의 수의 인스턴스를 지정한다.[15]

5. 클래스의 런타임 표현

대부분의 언어는 생성자와 소멸자를 통해 생명 주기 이벤트에 대한 사용자 정의 로직을 허용한다.[40] 언어나 라이브러리는 클래스에 대한 런타임 정보를 나타내는 프로토타입 또는 팩토리 메타객체를 지원할 수 있으며, 리플렉션 기능에 접근하고 런타임에 데이터 구조 형식을 조작할 수 있는 메타데이터를 나타낼 수도 있다. 많은 언어는 클래스에 대한 이러한 종류의 런타임 형식 정보를 런타임에 정보가 필요하지 않다는 점을 근거로 클래스와 구별한다. 일부 동적 언어는 런타임과 컴파일 타임 구조를 엄격하게 구분하지 않으므로 메타객체와 클래스를 구별하지 않을 수 있다.

예를 들어, Human이 Person 클래스를 나타내는 메타객체인 경우 Human 메타객체의 기능을 사용하여 Person 클래스의 인스턴스를 생성할 수 있다.

6. 프로토타입 기반 프로그래밍

일부 프로그래밍 환경에서는 프로토타입 객체를 복사(클로닝)하여 객체를 생성하는 것을 지원한다.[41]

7. 예제 코드

다음은 C# 코드 예제이다. `Program` 클래스는 C# 프로그램의 시작점인 `Main` 메소드를 포함하고 있다. `Console.WriteLine("Hello World");` 코드는 "Hello World" 문자열을 콘솔에 출력한다.

7. 1. C++ 예제

cpp

#include

using namespace std;

class A {

private:

int n;

public:

A(int n = 0); // 생성자 - 주로 객체의 상태(멤버변수 등)의 초기설정 등을 담당한다.

~A(); // 소멸자 - 객체 종료 시 필요한 조치를 취한다. 동적 변수 등의 제거를 하는 경우.

void SetN(int n);

int GetN();

};

A::A(int n) {

this->n = n;

}

A::~A() {

}

void A::SetN(int n) {

this->n = n;

return;

}

int A::GetN() {

return n;

}

int main() {

A a;

cout << a.GetN() << "\n";

a.SetN(10);

cout << a.GetN() << endl;

return 0;

}

```

결과:

```

0

10

```

다음은 C++에서의 클래스 예이다. 코드 실행 결과는 다음과 같다.

7. 2. C# 예제

csharp

using System;

namespace Main //클래스를 정의하기 위해 네임스페이스를 지정한다.

{

class Program //클래스를 정의한다.

{

static void Main(string[] args) //메소드를 지정한다. 이것은 메인메소드로 , 모든 C# 코드에 필수적이라고 할 수 있다.

{

Console.WriteLine("Hello World"); // Hello World를 콘솔에 출력한다.

}

}

}

```

결과:

```

Hello World

```

다음은 C# 코드 예제이다. `Program` 클래스는 `Main` 메소드를 포함하고 있으며, 이 메소드는 C# 프로그램의 시작점이다. `Console.WriteLine("Hello World");` 코드는 "Hello World" 문자열을 콘솔에 출력한다.

참조

[1] 웹사이트 3. Data model https://docs.python.[...] Python Software Foundation 2012-04-26
[2] 웹사이트 Classes (I) http://www.cplusplus[...] cplusplus.com 2012-04-29
[3] 웹사이트 Classes (II) http://www.cplusplus[...] cplusplus.com 2012-04-29
[4] 서적 New Perspectives on Computer Concepts 2016, Comprehensive Cengage Learning 2015-06-22
[5] 웹사이트 Controlling Access to Members of a Class http://docs.oracle.c[...] Oracle 2012-04-19
[6] 웹사이트 OOP08-CPP. Do not return references to private data https://web.archive.[...] Carnegie Mellon University 2010-05-10
[7] 웹사이트 2.2 Identifiers http://introcs.cs.pr[...] 2007-01-24
[8] 웹사이트 C++ Interfaces http://www.drdobbs.c[...] UBM Techweb 2012-05-02
[9] 웹사이트 Classes, Objects, and Variables http://ruby-doc.org/[...] Ruby-Doc.org 2012-04-26
[10] 웹사이트 Friendship and inheritance http://www.cplusplus[...] cplusplus.com 2012-04-26
[11] 웹사이트 UML-to-Java transformation in IBM Rational Software Architect editions and related software http://www.ibm.com/d[...] IBM 2008-12-02
[12] 서적 Object Oriented Software Engineering https://archive.org/[...] Addison-Wesley ACM Press
[13] 웹사이트 A Semantic Web Primer for Object-Oriented Software Developers http://www.w3.org/20[...] W3C 2006-03-09
[14] 웹사이트 Interfaces http://docs.oracle.c[...] Oracle 2012-05-01
[15] 웹사이트 UML Basics: The class diagram http://www.ibm.com/d[...] IBM 2012-05-02
[16] 웹사이트 Polymorphism http://www.cplusplus[...] cplusplus.com 2012-05-02
[17] 웹사이트 Abstract Methods and Classes http://docs.oracle.c[...] Oracle 2012-05-02
[18] 웹사이트 Class Abstraction http://php.net/manua[...] The PHP Group 2012-05-02
[19] 웹사이트 Interfaces (C# Programming Guide) http://msdn.microsof[...] Microsoft 2013-08-15
[20] 웹사이트 Inheritance (C# Programming Guide) http://msdn.microsof[...] Microsoft 2012-05-02
[21] 웹사이트 Nested classes (C++ only) http://publib.boulde[...] IBM 2012-05-07
[22] 웹사이트 Local type names (C++ only) http://publib.boulde[...] IBM 2012-05-07
[23] 웹사이트 Local classes (C++ only) http://publib.boulde[...] IBM 2012-05-07
[24] 웹사이트 13 Classes and metaclasses https://web.archive.[...] 2016-10-31
[25] 웹사이트 Classes and Objects http://www.ruby-doc.[...] Ruby-Doc.org 2012-05-08
[26] 웹사이트 MOP: Concepts https://web.archive.[...] Association of Lisp Users 2012-05-08
[27] 웹사이트 sealed (C# Reference) http://msdn.microsof[...] Microsoft 2012-05-08
[28] 웹사이트 Writing Final Classes and Methods http://docs.oracle.c[...] Oracle 2012-05-08
[29] 웹사이트 PHP: Final Keyword http://php.net/manua[...] The PHP Group 2014-08-21
[30] 웹사이트 String (Java Platform SE 7) http://docs.oracle.c[...] Oracle 2012-05-08
[31] 웹사이트 The Performance Benefits of Final Classes https://devblogs.mic[...] Microsoft 2020-03-02
[32] 웹사이트 9. Classes https://docs.python.[...] Python.org 2018-03-03
[33] 간행물 Partial Classes and Methods https://docs.microso[...] Microsoft 2015-09-19
[34] 웹사이트 Static Classes and Static Class Members (C# Programming Guide) http://msdn.microsof[...] Microsoft 2012-05-08
[35] 웹사이트 Anonymous Classes (The Java Tutorials > Learning the Java Language > Classes and Objects) https://docs.oracle.[...] 2021-05-13
[36] 웹사이트 PHP: Anonymous classes - Manual https://www.php.net/[...] 2021-08-11
[37] 웹사이트 What is an Object? http://docs.oracle.c[...] Oracle Corporation 2013-12-13
[38] 서적 Object-Oriented Analysis and Design with Applications http://my.safaribook[...] Addison-Wesley Professional 2013-12-20
[39] 서적 Object Oriented Software Engineering https://archive.org/[...] Addison-Wesley ACM Press
[40] 웹사이트 C++ International standard http://www.open-std.[...] ISO/IEC JTC1/SC22 WG21 2020-01-05
[41] 웹사이트 OOP - Object Oriented Programming - Concepts {{!}} Languages {{!}} Benefits [2023] https://www.thegeeks[...] 2023-04-04
[42] 문서 英語の class は、本来「分類」「種類」といった意味を持っている。
[43] 웹사이트 A History of C++: 1979−1991 http://www.stroustru[...] 2019-02-02
[44] 문서 落水(1993) p.82
[45] 문서 多くのプログラミング言語ではフィールドやメソッドの定義とアクセス権の指定は同時になされるため、カプセル化と情報隠蔽はしばしば混同される。
[46] 문서 構造化プログラミング(1975) p.226
[47] 문서 これが、ダールとホーアの論文の題名である『階層的プログラム構造』である。
[48] 웹사이트 INTRODUCTION TO SIMULA | WHAT IS WRONG WITH SIMULA ? http://staff.um.edu.[...]
[49] 문서 ただし、随所にOSの機能を利用することになるため異なるOSへの移植性が低い上に、主プログラムと並列呼び出しする従プログラムが異なる言語で記述されている場合、複数の異なるコンパイラが必要となり、場合によっては複数の異なる言語を使用しなければならなくなってしまう。
[50] 문서 構造化プログラミング(1975) pp.201-202
[51] 문서 構造化プログラミング(1975) p.202
[52] 문서 言語仕様にクラス構文を導入することで以下のような利益が得られる。* 主プログラムと従プログラムに相当するものが異なる言語で記述されることがない。* 複数スレッド計算機のOSに依存した以下の一連の操作を言語内部で統一的に処理できるようになる** 主プログラムからのメモリ割り当て** 並列呼び出し* 抽象データ型として表現される場合、OSを仲介した伝言のやりとりのような形式ではなく、体裁上は具体的データ型のデータに対する処理への引数渡し、処理返しとして取り扱い可能になる



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com