34-2-자.using 선언

using 선언은 다른 네임 스페이스의 명칭을 이 선언이 있는 곳으로 가져 오는 문장인데 클래스 계층 사이에서도 사용할 수 있다. 클래스 자체도 일종의 국지적인 네임 스페이스로 볼 수 있으므로 using 선언으로 원하는 명칭을 가져올 수 있다. 클래스에서 using 선언을 사용하면 기반 클래스 멤버의 액세스 속성을 원하는대로 변경하는 역할을 한다. 다음 예제를 보자.

 

: classusing1

#include <Turboc.h>

 

class B

{

private:

     void p() { puts("Base private function"); };

protected:

     void f() { puts("Base protected function"); }

public:

     void u() { puts("Base public function"); }

};

 

class D : public B

{

protected:

//  using B::u;

public:

//  using B::f;

     void f() { B::f(); }

};

 

void main()

{

     D d;

     d.f();

     d.u();

}

 

기반 클래스 B에 액세스 속성별로 세 개의 멤버 함수가 선언되어 있다. D는 이 클래스를 public 상속받았으므로 f 함수가 protected 속성으로 상속되며 u는 public 속성으로 상속된다. u는 외부에서도 호출가능하지만 protected 속성을 가지는 f는 D에서는 호출할 수 있지만 외부에서는 호출할 수 없다. 만약 f를 외부에서 호출할 수 있도록 하고 싶다면 두 가지 방법을 사용할 수 있다.

우선 이 함수를 public 영역에 같은 이름으로 재정의하는 방법을 쓸 수 있는데 이렇게 되면 B::f는 가려진다. 재정의된 f가 B::f를 대리 호출하면 외부에서도 이 함수를 호출할 수 있다. protected 액세스 속성을 가지는 멤버 함수가 재정의에 의해 public으로 이동한 것이다. 위 예제를 실행하면 main에서 d.f를 호출하는 것이 허가된다. D의 f 함수를 주석 처리하면 물론 호출할 수 없다.

두 번째 방법으로 using 선언을 사용하여 protected 영역에 있는 f 함수를 public 영역으로 명칭을 가져올 수 있다. 이렇게 되면 상속받은 f가 public 영역에 선언된 것과 같아져 외부에서도 이 함수를 호출할 수 있다. 재정의된 f 함수를 주석 처리하고 using 선언만 남겨 두어도 이 예제는 잘 실행된다. 둘 다 주석 처리하면 외부에서 f를 호출할 수 없다. using 선언은 public 영역에 있는 명칭을 protected로 숨길 수도 있다. B::u는 그대로 두면 public이지만 protected나 private로 옮겨 버리면 외부에서 호출할 수 없다.

using 선언은 접근 가능한 멤버의 액세스 속성을 변경하는 역할을 한다. 어디까지나 접근 가능한 멤버에 대해서만 이 지정을 사용할 수 있을 뿐인데 예제에서 B의 private 영역에 있는 p 함수를 public 영역에 두고 싶다고 해서 using B::p; 선언을 사용할 수는 없다. 자신도 접근하지 못하는 멤버에 대한 액세스 지정을 변경한다는 것 자체가 말이 되지 않는 것이다. 오로지 기반 클래스의 허가된 멤버(protected, public)만 using 선언을 사용할 수 있다.

다음 예제는 private 상속시 외부로 공개되지 않는 인터페이스를 공개하기 위해 using 선언을 사용한다.

 

: classusing2

#include <Turboc.h>

 

class B

{

protected:

     void f() { puts("Base protected function"); }

public:

     int m;

};

 

class D : private B

{

protected:

     using B::m;

public:

     using B::f;

};

 

class G : public D

{

public:

     void gf() {

          m=1234;

     }

};

 

void main()

{

     D d;

     d.f();

//  d.m=1234;

}

 

D는 B를 private 상속받았으므로 B의 f, m 멤버는 모두 private가 될 것이다. 이 상태에서는 D 외부나 파생 클래스에서 상속받은 멤버를 액세스할 수 없는 것이 정상이다. 하지만 D가 using 선언으로 이 멤버들의 액세스 속성을 변경하였으므로 변경된 속성대로 액세스가 허가된다. f의 경우 public 영역에 using 선언했으므로 클래스 외부인 main에서 이 함수를 호출할 수 있다. m의 경우 protected 영역에 using 선언했으므로 이차 파생 클래스인 G가 이 멤버를 참조할 수 있다. 하지만 main에는 m을 읽을 수 없다.