Is-a
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
is-a 관계는 객체 지향 프로그래밍에서 사용되는 개념으로, 한 유형(클래스)이 다른 유형의 하위 유형임을 나타내는 관계를 의미한다. 이는 has-a 관계, instance-of 관계와 대조되며, 상속, 서브타이핑, 리스코프 치환 원칙과 밀접한 관련이 있다. C++, Python, Java 등의 프로그래밍 언어에서 is-a 관계를 표현하는 다양한 방법을 제공하며, 특히 서브타이핑은 is-a 관계를 통해 형식 간의 대체 가능성을 정의한다.
''is-a'' 관계는 객체 지향 프로그래밍에서 사용되는 다른 관계들과 비교하여 이해할 수 있다.
2. 관련 개념
''is-a'' 관계는 유형(클래스) 간의 ''has-a'' 관계 및 객체(인스턴스)와 유형(클래스) 간의 ''instance-of'' 관계와 대조된다. 유형-토큰 구분 참고.
''is-a'', ''has-a'', ''instance-of'' 관계는 다음과 같이 요약할 수 있다.관계 설명 종류 상위어–하위어 관계 분류 계층을 정의하는 유형(클래스) 간의 관계 포괄 관계 전체어–부분어 관계 소유 계층을 정의하는 유형(클래스) 간의 관계 개념–객체(유형–토큰) 관계 유형(클래스)과 객체(인스턴스) 간의 관계 instance-of 관계
2. 1. has-a 관계와의 비교
''has-a''(has_a 또는 has a) 관계는 유형(클래스) 간의 ''is-a'' 관계와 대조된다. ''has-a''와 ''is-a'' 관계를 혼동하는 것은 객체와 하위 객체 간의 실제 관계 모델(예: 컴퓨터 프로그램)을 설계할 때 흔히 발생하는 오류이다.
관계는 다음과 같이 요약할 수 있다.
| 관계 | 설명 | 종류 |
|---|---|---|
| 상위어–하위어(상위 유형/슈퍼클래스–하위 유형/서브클래스) 관계 | 분류 계층을 정의하는 유형(클래스) 간의 관계 | 포괄 관계: 하위어(하위 유형, 서브클래스)는 상위어(상위 유형, 슈퍼클래스)와 type-of(is-a) 관계를 갖는다. |
| 전체어–부분어(전체/개체/컨테이너–부분/구성 요소/구성원) 관계 | 소유 계층을 정의하는 유형(클래스) 간의 관계 |
2. 2. instance-of 관계와의 비교
''instance-of'' 관계는 객체가 특정 클래스의 인스턴스인지를 확인하는 관계이다. 예를 들어, '특정 자동차 객체는 자동차 클래스의 인스턴스이다'는 ''instance-of'' 관계이다. ''is-a'' 관계는 클래스 간의 상속 관계를 나타내는 반면, ''instance-of'' 관계는 객체와 클래스 간의 관계를 나타낸다.[2]- 개념–객체(유형–토큰) 관계는 유형(클래스)과 객체(인스턴스) 간의 관계이다.
- * 토큰(객체)은 해당 유형(클래스)과 ''instance-of'' 관계를 갖는다.
2. 3. 상위어-하위어 관계
상위어-하위어(상위 유형/슈퍼클래스-하위 유형/서브클래스) 관계는 분류 계층을 정의하는 유형(클래스) 간의 관계이며, 포괄 관계의 경우 하위어(하위 유형, 서브클래스)는 상위어(상위 유형, 슈퍼클래스)와 ''type-of''(''is-a'') 관계를 갖는다.[2]2. 4. 전체어-부분어 관계
전체어-부분어(전체-부분) 관계는 has-a 관계와 유사하며, 집계 또는 구성 관계로 표현된다. 집계 관계는 전체 객체가 부분 객체를 포함하지만, 부분 객체의 생명 주기는 전체 객체에 종속되지 않는다. 구성 관계는 전체 객체가 부분 객체를 포함하고, 부분 객체의 생명 주기는 전체 객체에 종속된다.- 집계 관계 (소유권 없음):
- 전체어(전체)는 부분어(부분)와 ''has-a'' 관계를 갖는다.
- 구성 관계 (소유권 있음):
- 부분어(구성 요소)는 전체어(개체)와 ''part-of'' 관계를 갖는다.
- 포함[2] 관계:
- 부분어(구성원)는 전체어(컨테이너)와 ''member-of'' 관계를 갖는다.
3. 서브타이핑
서브타이핑은 주어진 형식이 다른 형식 또는 추상화로 대체될 수 있도록 하는 기능이다. 서브타이핑은 언어 지원에 따라 암시적으로 또는 명시적으로 서브타입과 기존 추상화 간에 '''is-a''' 관계를 설정한다고 한다. 상속을 서브타이핑 메커니즘으로 지원하는 언어에서는 상속을 통해 이러한 관계를 명시적으로 표현할 수 있다.
서브타이핑을 통해 하위 클래스의 객체를 상위 클래스의 객체처럼 사용할 수 있으며, 이는 다형성을 구현하는 데 중요한 역할을 한다.
3. 1. C++에서의 서브타이핑
C++에서는 상속을 통해 is-a 관계를 명시적으로 표현할 수 있다. 하위 클래스는 상위 클래스의 public 및 protected 멤버를 상속받으며, 상위 클래스 객체가 필요한 곳에 하위 클래스 객체를 사용할 수 있다.[1]다음은 C++ 코드 예시이다.
```cpp
class A
{
public:
void DoSomethingALike() const {}
};
class B : public A
{
public:
void DoSomethingBLike() const {}
};
void UseAnA(A const& some_A)
{
some_A.DoSomethingALike();
}
void SomeFunc()
{
B b;
UseAnA(b); // b는 A로 대체될 수 있습니다.
}
```
위 코드에서 클래스 '''B'''와 '''A''' 간의 명시적인 상속 관계를 설정하며, 여기서 '''B'''는 '''A'''의 하위 클래스이자 하위 유형이며, '''B'''가 지정된 모든 위치에서 '''A'''로 사용될 수 있다(참조, 포인터 또는 객체 자체를 통해).[1]
3. 2. Python에서의 서브타이핑
pythonclass A:
def do_something_a_like(self):
pass
class B(A):
def do_something_b_like(self):
pass
def use_an_a(some_a):
some_a.do_something_a_like()
def some_func():
b = B()
use_an_a(b) # b는 A를 대체할 수 있다.
```
위 파이썬 코드에서 클래스 B는 클래스 A를 상속받는다. 즉, B는 A의 서브클래스이자 서브타입이다. 따라서 B는 A가 필요한 모든 곳에서 A를 대체하여 사용될 수 있다.[4]
```pycon
>>> a = 0
>>> type(a)
>>> type(type(a))
>>> type(type(type(a)))
>>> type(type(type(type(a))))
```
위 예제에서 `type(a)`는 "일반" 타입이고, `type(type(a))`는 메타타입이다. 배포된 모든 타입은 동일한 메타타입(`PyType_Type`, 이는 자체 메타타입이기도 함)을 갖지만, 이것이 필수 사항은 아니다. `types.ClassType`으로 알려진 고전 클래스의 타입은 별개의 메타타입으로 간주될 수도 있다.[4]
3. 3. Java에서의 서브타이핑
Java에서 한 클래스 또는 인터페이스의 타입 매개변수와 다른 클래스 또는 인터페이스의 타입 매개변수 간의 '''is-a''' 관계는 extends 및 implements 절에 의해 결정된다.[1]`Collections` 클래스를 사용하면, `ArrayList
```java
interface PayloadList
void setPayload(int index, P val);
...
}
```
다음 `PayloadList`의 매개변수화는 `List
```java
PayloadList
PayloadList
PayloadList
4. 리스코프 치환 원칙
리스코프 치환 원칙은 ''"S형식의 각 객체 o1에 대해 T형식의 객체 o2가 있어 T를 기준으로 정의된 모든 프로그램 P에 대해 o1을 o2로 대체할 때 P의 동작이 변경되지 않으면 S는 T의 하위 형식이다."''라는 속성을 설명한다.[5]
이는 객체 지향 프로그래밍의 SOLID 원칙 중 하나로, is-a 관계의 중요한 제약 조건을 설명한다. LSP에 따르면, 하위 클래스의 객체는 상위 클래스의 객체를 대체할 수 있어야 하며, 프로그램의 동작은 변경되지 않아야 한다. LSP를 위반하는 대표적인 예시는 정사각형-직사각형 문제이다.
4. 1. 리스코프 치환 원칙 위반 사례 (정사각형-직사각형 문제)
cppclass Rectangle
{
public:
void SetWidth(double w) { itsWidth = w; }
void SetHeight(double h) { itsHeight = h; }
double GetHeight() const { return itsHeight; }
double GetWidth() const { return itsWidth; }
double GetArea() const { return GetHeight() * GetWidth(); }
private:
double itsWidth;
double itsHeight;
};
```
프로그래밍 관점에서 Square 클래스는 Rectangle 클래스를 상속하여 구현될 수 있다.
```cpp
public class Square : Rectangle
{
public:
virtual void SetWidth(double w);
virtual void SetHeight(double h);
};
void Square::SetWidth(double w)
{
Rectangle::SetWidth(w);
Rectangle::SetHeight(w);
}
void Square::SetHeight(double h)
{
Rectangle::SetHeight(h);
Rectangle::SetWidth(h);
}
```
그러나 이것은 Rectangle과 Square 사이에 '''is-a''' 관계가 성립함에도 LSP를 위반한다.
Square가 전달될 경우 함수 g가 작동하지 않는 다음 예시를 고려하면 개방-폐쇄 원칙이 위반된 것으로 간주될 수 있다.
```cpp
void g(Rectangle& r)
{
r.SetWidth(5);
r.SetHeight(4);
assert(r.GetArea() == 20); // assertion will fail
}
```
반대로, 도형의 형식은 치수에 대한 제약 조건일 뿐이라고 생각한다면, g()에서 SetHeight가 높이와 면적은 변경하지만 너비는 변경하지 않는다는 가정은 유효하지 않다. 이는 실제 정사각형뿐만 아니라 높이가 변경될 때 면적이나 종횡비를 유지하도록 코딩될 수 있는 다른 직사각형에도 해당된다.[6]
참조
[1]
웹사이트
Subtypes and Subclasses
http://ocw.mit.edu/c[...]
MIT OCW
2012-10-02
[2]
문서
Containment (computer programming)
[3]
서적
Concepts in programming language
Cambridge University Press
[4]
웹사이트
Subtyping Built-in Types
https://www.python.o[...]
2012-10-02
[5]
서적
Data Abstraction and Hierarchy
https://klevas.mif.v[...]
SIGPLAN Notices
1988-05
[6]
웹사이트
The Liskov Substitution Principle
http://www.objectmen[...]
Robert C. Martin, 1996
2012-10-02
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com