-
has-a 설계 방법카테고리 없음 2014. 1. 21. 22:26
- 상속관계 (Has-a)
A가 B를 가진다고 할때 A가 B를 상속하여서 B의 public method를 통해서 접근을 하는 방법이다.
틀린 것은 아니나 상속관계의 강한 Coupling으로 A/B Class의 변경사항이 있을 때 Class 전체를 다시 설계해야 하는 문제가 있다.
- Composition (Containment)
타 클래스 객체를 멤버로 갖는 클래스를 만든다. (일반적으로 가지게 되는 객체는 private 멤버이다.) 이렇게 하면 외부에서는 내부에 포함된 클래스 멤버의 메소드에 접근이 불가능하며, A가 B를 가진다고 할때, B의 메소드에 접근하려면, A의 public 메소드를 통해서만 접근이 가능하다.
class CB {
private:
...
public:
void funcB();
};
class CA :
{
private:
CB Cbase;
public:
void funcA();
void accessfuncB();
};
Main () {
Cbase.funcB();
}
- private 상속
상속을 private로 하면 기초 클래스의 public, protected 멤버가 파생클래스에서는 private 멤버가 된다. 즉, 외부에서 기초 클래스 메소드, 멤버를 직접 건드릴 수가 없으나, 파생 클래스 내부에서는 접근이 가능하다.
private 상속의 특징은 종속되는 객체의 이름이 없다. (컨테인먼트는 내부에서 객체선언을 하므로 이름을 가진다.) 그러므로 B클래스의 메소드에 접근을 하기 위해서는 사용범위 결정 연산자(::)를 써야 한다.
class CB
{
private:
...
public:
void funcB();
};
class CA : private CB
{
private:
...
public:
void funcA();
CB & funcA2();
};
// CA가 CB를 가진다. (has - a)
A의 메소드 funcA()가 있다면, B의 메소드에 접근하고자 할때, A 메소드 내에서..
void CA::funcA()
{ CB::funcB(); }
이와 같이 접근해야 한다. ( funcB()가 B클래스 내에서 private였다면 애당초 접근이 불가함 )
→ 객체 부분에 접근하기 위해서는 타입 캐스트 연산자를 붙여야 한다.
CB & CA::funcA2()
{ return ( CB & ) *this; }
*this가 CA 객체를 뜻하는데, CB의 참조로 타입캐스트 연산을 했으므로 기초 클래스 부분인 CB에 대한 접근이 가능하다.
* 두개의 has-a 사용 방법은 차이점이 다소 있다. 또한 각각의 장단점도 가지고 있다.
1. 컨테인먼트
- 장점
1) 사용이 쉽다.
2) 객체의 이름을 가진다.
3) 동일 타입 클래스를 여러개 종속 할 수가 있다.
- 단점
1) 종속 클래스의 protected 멤버에 접근이 불가능하다.
→ CA클래스의 경우 CB에게 상속받은 것이 아니기 때문에 CA측면에서 보면 CB는 외부가 되버린다. 즉, protected 멤버에는 접근이 불가능하다.
2) 순수가상함수 문제
→ CA클래스에 만약 순수 가상함수가 있다면 CB내에서 CA객체 생성이 불가능하기 때문에 종속 시킬 수가 없다.
2. private 상속
- 장점
1) protected 멤버에 접근이 가능하다.
2) CB에 순수 가상함수가 있다해도 쓸 수 있으며, 가상함수 오버라이딩(재정의)이 가능해 진다. 단, private 상속에서는 오버라이딩되는 함수가 public으로 사용할 수 없고 private로 써야 한다.
- 단점
1) 동일 타입클래스를 한종류에 한개만 종속 가능하며 한 클래스 종류에 두개 이상의 객체를 종속 시킬 수 없다.
2) 종속을 여러 클래스로 할 경우 다중 상속을 해야 하며, 그에 따른 문제점이 존재한다.
3) 종속 객체에 이름이 없으므로 접근이 다소 복잡해 질 수 있다.
* protected 상속
→ 이것의 특징은 기초 클래스의 public, protected 멤버가 파생 클래스에서는 protected 멤버가 된다. 이 파생 클래스를 기초로 하여 또 다른 파생 클래스를 만들시 주로 사용된다.