다중상속 .. 이거 가능한지?

dalmagi의 이미지

외부에서 얻어온 어떤 클래스를 소스 수정없이 내가 만든 클래스의 구현체로 사용하려고 합니다.
즉, 하나의 가상클래스를 작성한 후 그것을 상속받은 클래스에서 직접 구현하지 않고 대신 외부의 클래스를 다중으로 상속받아서 마치 자신이 구현한 것처럼요.
이렇게 해보았습니다.

//---------------------------------------------------------------------------

#include <stdio.h>

//---------------------------------------------------------------------------
class greet_eng_impl //  외부 클래스 
public:
		void hello(){printf("hello");};
};
//--------------------------------
class greet
{
	public:
		virtual void hello()=0;
};

class greet_eng : public greet, public greet_eng_impl // 다중으로 상속
{
	// 비어둠
};
//--------------------------------


int main(int argc, char* argv[])
{
	greet *g = new greet_eng;
	g->hello();
	delete g;

	return 0;
}
//---------------------------------------------------------------------------

비슷한 역할을 하는 많은 클래스들이 있는데 이놈들을 소스수정없이 통합시켜 슈퍼클래스를 작성하려고 하다보니 별 방법이 없어서 C++ 에 있다는 다중상속을 함 둘러보고 있습니다. 이럴때 사용하라고 만든건 아닌것 같습니다만 호기심 차원에서 함 시도 해봤는데 되지는 않네요. 스위치문 같은거 없이 폴리모피즘을 이루려면 어떻게 해야하나요?
익명 사용자의 이미지

pure virtual 함수 때매 instantiation이 될 리가 없지요.
자바에서도 멤버 함수를 구현안한 abstract class는 istantiation 안되지요.
다중 상속시에는 네임 충돌도 신경 써야 합니다.

only2sea의 이미지

df wrote:
외부에서 얻어온 어떤 클래스를 소스 수정없이 내가 만든 클래스의 구현체로 사용하려고 합니다.
즉, 하나의 가상클래스를 작성한 후 그것을 상속받은 클래스에서 직접 구현하지 않고 대신 외부의 클래스를 다중으로 상속받아서 마치 자신이 구현한 것처럼요.
이렇게 해보았습니다.
//---------------------------------------------------------------------------

#include <stdio.h>

//---------------------------------------------------------------------------
class greet_eng_impl //  외부 클래스 
public:
		void hello(){printf("hello");};
};
//--------------------------------
class greet
{
	public:
		virtual void hello()=0;
};

class greet_eng : public greet, public greet_eng_impl // 다중으로 상속
{
	// 비어둠
};
//--------------------------------


int main(int argc, char* argv[])
{
	greet *g = new greet_eng;
	g->hello();
	delete g;

	return 0;
}
//---------------------------------------------------------------------------

비슷한 역할을 하는 많은 클래스들이 있는데 이놈들을 소스수정없이 통합시켜 슈퍼클래스를 작성하려고 하다보니 별 방법이 없어서 C++ 에 있다는 다중상속을 함 둘러보고 있습니다. 이럴때 사용하라고 만든건 아닌것 같습니다만 호기심 차원에서 함 시도 해봤는데 되지는 않네요. 스위치문 같은거 없이 폴리모피즘을 이루려면 어떻게 해야하나요?

원하시는 건지는 모르겠지만 class greet_eng의 내부를 비워두지 마시고,

        void hello()
        {
            greet_eng_impl::hello();
        }

이런건 어떤가요? 생각해보시면 class greet_eng의 인스턴스가 만들어진 상황에서 그 인스턴스에 호출될 때 invoke되는 것은 greet_eng_impl에서 구현한 것이 되겠지요. 항상 그렇지요. 따라서 polymorphic에도 어긋나지 않습니다. 만약 greet을 상속받은 다른 클래스가 있고 이 클래스의 인스턴스가 만들어진 상황에서 호출을 하면 그 클래스에 있는 메소드가 호출이 되죠.

대신에 greet에 있는 각각의 가상 메소드마다 greet_eng에서 저것을 집어넣어줘야 한다는 점이죠.

Kroisse의 이미지

개인적인 의견이지만, 다중 상속보다는 포함과 위임을 사용하는 게 어떨까요?

//---------------------------------------------------------------------------

#include <stdio.h>

//---------------------------------------------------------------------------
class greet_eng_impl //  외부 클래스
public:
      void hello(){printf("hello");};
};
//--------------------------------
class greet
{
   public:
      virtual void hello()=0;
};

class greet_eng : public greet
{
   public:
      virtual void hello() { composedObject.hello(); }  // hello의 처리를 composedObject에 위임
   private:
      greet_eng_impl composedObject;   // greet_eng_impl의 인스턴스를 포함
};
//--------------------------------


int main(int argc, char* argv[])
{
   greet *g = new greet_eng;
   g->hello();
   delete g;

   return 0;
}
//--------------------------------------------------------------------------- 
dalmagi의 이미지

아 감사합니다.
인터페이스+결합+위임
이렇게 쓰면 깔끔하게 되는군요. 이게 정석인 것 같네요.
C++ 은 아닙니다만 이렇게 했습니다.

program Test;

type

  TGreetEngImpl = class
    procedure Hello;
  end;

  IGreet = interface
    procedure Hello;
  end;

  TGreetEng = class(TInterfacedObject, IGreet)
    FGreetEngImpl: TGreetEngImpl;
    property GreetEngImpl: TGreetEngImpl read FGreetEngImpl implements IGreet;
  end;

{ TGreetEngImpl }

procedure TGreetEngImpl.Hello;
begin
  writeln('hello');
end;

var
  Greet: IGreet;
  GreetEng: TGreetEng;

begin
  GreetEng := TGreetEng.Create;
  GreetEng.FGreetEngImpl := TGreetEngImpl.Create;
  Greet := GreetEng;
  Greet.Hello;
end.

찾아보니 C# 엔 delegate 란 문법적 지원도 있더군요.
암튼 넘 고맙습니다 많이 배웠습니다.

화이팅(fighting) 말고 화이트닝(whitening) 하면 안되나요.

only2sea의 이미지

df wrote:
아 감사합니다.
인터페이스+결합+위임
이렇게 쓰면 깔끔하게 되는군요. 이게 정석인 것 같네요.
C++ 은 아닙니다만 이렇게 했습니다.
program Test;

type

  TGreetEngImpl = class
    procedure Hello;
  end;

  IGreet = interface
    procedure Hello;
  end;

  TGreetEng = class(TInterfacedObject, IGreet)
    FGreetEngImpl: TGreetEngImpl;
    property GreetEngImpl: TGreetEngImpl read FGreetEngImpl implements IGreet;
  end;

{ TGreetEngImpl }

procedure TGreetEngImpl.Hello;
begin
  writeln('hello');
end;

var
  Greet: IGreet;
  GreetEng: TGreetEng;

begin
  GreetEng := TGreetEng.Create;
  GreetEng.FGreetEngImpl := TGreetEngImpl.Create;
  Greet := GreetEng;
  Greet.Hello;
end.

찾아보니 C# 엔 delegate 란 문법적 지원도 있더군요.
암튼 넘 고맙습니다 많이 배웠습니다.

델파이군요. 개인적으로 좋아하는 랭기지입니다.
실제로 다중상속을 쓰셔서 결합(glue) 형태로 동작할 겁니다.
irondog의 이미지

only2sea wrote:
df wrote:
아 감사합니다.
인터페이스+결합+위임
이렇게 쓰면 깔끔하게 되는군요. 이게 정석인 것 같네요.
C++ 은 아닙니다만 이렇게 했습니다.
program Test;

type

  TGreetEngImpl = class
    procedure Hello;
  end;

  IGreet = interface
    procedure Hello;
  end;

  TGreetEng = class(TInterfacedObject, IGreet)
    FGreetEngImpl: TGreetEngImpl;
    property GreetEngImpl: TGreetEngImpl read FGreetEngImpl implements IGreet;
  end;

{ TGreetEngImpl }

procedure TGreetEngImpl.Hello;
begin
  writeln('hello');
end;

var
  Greet: IGreet;
  GreetEng: TGreetEng;

begin
  GreetEng := TGreetEng.Create;
  GreetEng.FGreetEngImpl := TGreetEngImpl.Create;
  Greet := GreetEng;
  Greet.Hello;
end.

찾아보니 C# 엔 delegate 란 문법적 지원도 있더군요.
암튼 넘 고맙습니다 많이 배웠습니다.

델파이군요. 개인적으로 좋아하는 랭기지입니다.
실제로 다중상속을 쓰셔서 결합(glue) 형태로 동작할 겁니다.

오~ 향수어린 랭귀지~ VCL의 구조가 참 간결하고 좋았던거 같아요. 볼랜드 C++도 같은걸 썼던거 같은데. MFC에 밀려 아쉽게 됐죠? ^^

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.