Turbo-C
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
터보-C 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
Lua 게시판
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C/C++ 강좌/문서
[35] (06) Virtual, Friend in C++ (1)
남병철.레조 [lezo] 11319 읽음    2009-06-21 12:11


[목차]

(1) 가상함수를 이용한 다형성
(2) 추상 Class와 가상 파괴자
(3) RTTI (RunTime Type Identification)
(4) 프렌드 함수
(5) 프렌드 Class
(6) 내포 Class와 정적 멤버 데이타










(1) 가상함수를 이용한 다형성

    - 가상함수의 개념

    객체지향 프로그래밍의 세 가지 주요 개념
    1. 클래스(Class)
    2. 상속성(Inheritance)
    3. 다형성(Polymorphism)

    다형성 : 대개 다형성은 상속성과 관련된 클래스에서 일어난다.
             C++의 다형성은 구성원 함수 호출이 함수를 호출하는 객체의 유형에 따라
             서로 다른 함수를 실행시킨다는 것을 의미한다.

    겹지정과 다형성의 차이점
    : 함수 겹지정에서는 컴파일러를 통해 선택이 이루어진다.
    : 다형성에서는 프로그램이 실행되는 동안에 선택이 이루어진다.
      함수 겹지정은 단지 클래스 사용자의 편의를 위한 것인 반면, 다형성은 프로그램
      전체 체계에 영향을 미친다.



    - 가상함수의 내부 동작

    일반객체(가상함수가 없는 객체)는 자체의 데이타만 포함하고 다른 것은 전혀 포한하고
    있지 않다. 이 객체의 구성원 함수가 호출될 때, 컴파일러는 함수에 호출 객체의 주소를
    전달한다.(객체와 구성원 함수간의 관계)
    이 주소는 this포인터에서 사용할 수 있다.
    함수는 그 주소를 사용하여 객체의 데이터에 접근한다.(내부적으로, 보이지않게)
    또한, this의 주소는 구성원 함수가 호출될 때마다 컴파일러에 의해서 생성된다.
    this 포인터는 객체와 그 객체의 일반 구성원 함수 사이에 필요한 연결일 뿐이다.

    가상 함수에서는 일이 좀 복잡해진다.
    가상 함수를 가진 유도클래스가 지정 되면, 컴파일러는 가상표(VTable)라는 
    가상 함수 주소의 표(배열)를 만든다. 표의 이름은 컴파일러에 따라 다르다.
    각 가상표에는 해당 클래스(ex Derv1)의 모든 가상 함수에 대한 항목이 있다.
    (같은 Base Class에서 유도된 서로다른 Derv1 Class, Derv2 Class는 VTable의 배열
     순서 및 함수 이름항목이 같지만 VTable의 주소는 Class에 대해 서로 다르다.
     또한 VTable이 가지고있는 많은 항목(해당 구성원 함수 포인터들)들의 주소역시
     다르다.)
    Derv1이나 Derv2의 모든 객체는 구성될 당시에 자체의 데이터 외에 포인터를 더
    포함하고 있다. 즉, 하나 이상의 가상함수를 가진 클래스의 모든 객체들은 마찬가지로
    일반 객체보다 VTable 포인터를 가지고 있으므로 좀더 크다.

    가상 함수가 호출되게 되면, 컴파일러는 VTable을 채크해서 해당 클래스의 적절한
    구성원 함수에 접근한다. 즉, 가상 함수에서는 컴파일러가 아니라 객체 자체가 호출
    함수를 결정한다.

    가상 함수에 사용한 객체 포인터는 대개 독립 변수에 저장되지 않고 배열에 저장되어
    사용한다.
    배열에 저장된 객체 포인터의 형을 인식하여 호출할 show();의 버전을 알아 낸다.
    또한 메인의 for를 보면 호출을 수행하는 형태에 따라 하나의 함수 호출로 많은
    함수를 호출할 수 있다.(여기서는 Derv1의 show() 와 Derv2의 show())
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.15
// 제  목 : 객체 포인터 배열과 가상함수
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

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

class Base
{
public:
    virtual void show() {
        cout << "\nBase";
    }
};

/////////////////////////////////////////////////////////////////////////////

class Derv1 : public Base
{
public:
    void show() {
        cout << "\nDerv1";
    }
};

/////////////////////////////////////////////////////////////////////////////

class Derv2 : public Base
{
public:
    void show() {
        cout << "\nDerv2";
    }
};

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

#pragma argsused
void main()
{

    Base* arrBase[2];
    Derv1 dv1;
    Derv2 dv2;

    arrBase[0] = &dv1;
    arrBase[1] = &dv2;

    for( int j = 0; j < 2; j++ )
        arrBase[j]->show();

    getch();

}

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

(결과)
Derv1
Derv2

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------]
// 작성일 : 2006.05.26
// 제  목 : 객체 포인터와 가상함수
// 작성자 : 남병철
//---------------------------------------------------------------------------
#include 
//---------------------------------------------------------------------------
class Base
{
public:
	virtual ~Base()
	{ cout << "\nBase destructor"; }
	virtual void P()
	{ cout << "\n Base P"; }
	void B()
	{ cout << "\n Base B"; }
};
//---------------------------------------------------------------------------
class Derv : public Base
{
public:
	~Derv()
	{ cout << "\nDerv destructor"; }
	void P()
	{ cout << "\n Derv P"; }
	void B()
	{ cout << "\n Derv B"; }
};
//---------------------------------------------------------------------------
class SubDerv : public Derv
{
public:
	~SubDerv()
	{ cout << "\nSubDerv destructor"; }
	void P()
	{ cout << "\n SubDerv P"; }
	void B()
	{ cout << "\n SubDerv B"; }
};
//---------------------------------------------------------------------------
class BottomDerv : public SubDerv
{
public:
	~BottomDerv()
	{ cout << "\nBottomDerv destructor"; }
	void P()
	{ cout << "\n BottomDerv P"; }
	void B()
	{ cout << "\n BottomDerv B"; }
};
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
	Base* pb = new BottomDerv;
	pb->P();
	pb->B();
	delete pb;
	cout << "\nProgram terminates";
	return 0;
}
//---------------------------------------------------------------------------

(결과)
 BottomDerv P
 Base B
BottomDerv destructor
SubDerv destructor
Derv destructor
Base destructor
Program terminates
** 결론 ** 가상 함수는 상대적 최상위 클래스에 한번 선언되어 있으면 그 하위의 같은 함수는 모두 가상함수를 의미하므로 최상위(or상위) 클래스 타입으로 선언하여 자신이 원하는타입의 객체 포인터(BottomDerv)를 다룰 수 있다. 이는 dynamic_cast를 통해 최상위(or상위) 클래스의 타입으로 생성한(new) 객체의 타입을 캐스팅하는 RTTI 코딩이 가능함을 의미한다. 즉, Base* pb = new BottomDerv; 가상 함수가 아닐경우 왼쪽의 선언타입인 Base 클래스의 메소드가 실행되며 pb->B();의 결과 : Base B 가상 함수일 경우 오른쪽의 생성 객체 BottomDerv 타입의 메소드가 실행된다. pb->P();의 결과 : BottomDerv P 물론 계층에 역행하는 사용은 컴파일러에 의해 제한된다. Ex) BottomDerv* pb = new Base; //--------------------------------------------------------------------------- - 객체에서의 가상함수 Class 선언은 위 소스와 동일(Base Class만 제외)
    void main()
    {
        Base arrObjs[2];
        Derv1 dv1;
        Derv2 dv2;

        arrObjs[0] = dv1;
        arrObjs[1] = dv2;

        for( j = 0; j < 2; j++ )
            arrObjs[j].show();
    }

    Result:
    Base
    Base
객체 포인터가 아닌 객체를 사용했을 경우는 왜이런 결과가 나오는가? 유도 Class의 객체가 기초 Class의 객체와 같은 크기로 되어 있지 않을 수 있다. 유도 Class는 기초 Class와 '동족' 관계를 유지하기 위한 추가 데이타가 대개 들어 간다. 그렇지 않더라도 유도 Class 객체는 기초 Class에 들어가면서 메모리상으로 넘치는 크기만큼이 잘려진다. 결국 유도 클래스 부분은 사라지게 된다. 하지만 포인터를 사용할 경우 그 가리키는 Class가 무엇이든 유도 Class의 주소를 기초 Class 포인터에 넘겨도 그 크기는 일정하므로 유도 Class의 내용이 손상받지 않게된다. 즉, 다형성을 사용하려면 객체가 아니라 객체 포인터(또는 포인터로 위장한 참조)를 가지고 가상 함수를 호출하라는 것이다. - 가상 함수 예제 아래의 shape Class는 객체화 하지 않는다. 단지 square, cap, bowl Class의 기초 클래스 역할만할 뿐이다. ( shape을 객체화해서 draw()하면 에러 메시지가 난다. -> 서투르다 ) 순가상 함수를 사용하면 에러 메시지를 컴파일 타임에 잡아낼 수 있다. 또한 배열을 객체들로 채워 넣으려면 객체의 생성자를 사용하는것(아래)이 예제 소스보다 더 낫다. // 객체의 생성자를 사용
    shape* sharray[N] = { &bowl( 10, 0, 3 ),
                          &square( 20, 1, 5 ),
                          ∩( 30, 1, 7 )
                        };
객체의 생성자는 객체가 생성되기 시작하는 첫 번째 장소에서 그 가상 메커니즘(vptr)을 설정했기 때문에 그럴 수 없다.( 물론 객체에 메모리를 할당하는 코드를 볼 수 없듯이, 이에 대한 코드도 볼 수 없다. ) 또한 객체를 만들때는 대부분 객체의 종류를 컴파일러가 알 수 있으므로 기존에 존재하는, 객체 포인터에 접근하는, 가상 함수에는 가상 생성자가 별 필요성이 없다. 하지만 파괴자는 가상일 수 있고 그 필요성도 높다.
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.23
// 제  목 : Virtual Function 그래픽 예제
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------
#pragma argsused
//---------------------------------------------------------------------------
class shape
{
private:
    int xCo, yCo;
    int size;

protected:
    int getx() const { return xCo; }
    int gety() const { return yCo; }
    int getz() const { return size; }
    void down() const;      // preDefine

public:
    // 3인수 생성자
    shape( int x, int y, int s ) : xCo( x ), yCo( y ), size( s ) {}
    virtual void draw() const {
        cout << "Error : base virtual" << endl;
    }
};


// Define void shape::down() const
void shape::down() const
{
    for( int y = 0; y < yCo; y++ )
        cout << endl;
}

/////////////////////////////////////////////////////////////////////////////

class square : public shape
{
public:
    // 3인수 생성자
    square( int x, int y, int s ) : shape( x, y, s ) {}
    void draw() const;
};


// 정사각형을 그린다.
void square::draw() const
{
    shape::down();  // 도형의 윗부분에 y를 위치시킨다.

    // 도형을 가로질러 y를 위치시킨다.
    for( int y = 0; y < getz(); y++ ) {
        int x;
        for( x = 1; x < getx(); x++ )   // 도형이 있는곳 까지 빈칸으로 감
            cout << ' ';
        for( x = 0; x < getz(); x++ )   // X자로 된 줄을 그린다.
            cout << 'X';
        cout << endl;
    }
}

/////////////////////////////////////////////////////////////////////////////

class cap : public shape
{
public:
    // 3인수 생성자
    cap( int x, int y, int s ) : shape( x, y, s ) {}

    void draw() const;
};

void cap::draw() const
{
    shape::down();
    for( int y = 0; y < getz(); y++ ) {
        int x;
        for( x = 0; x < getx() - y + 1; x++ )
            cout << ' ';
        for( x = 0; x < 2*y+1; x++ )
            cout << 'X';
        cout << endl;
    }
}

/////////////////////////////////////////////////////////////////////////////

class bowl : public shape
{
public:
    bowl( int x, int y, int s ) : shape( x, y, s ) {}
    void draw() const;
};

void bowl::draw() const
{
    shape::down();
    for( int y = 0; y < getz(); y++ ) {
        int x;
        for( x = 0; x < getx() - ( getz() - y ) + 2; x++ )
            cout << ' ';
        for( x = 0; x < 2 * ( getz() - y ) - 1; x++ )
            cout << 'X';
        cout << endl;
    }
}

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

void main()
{

    const int N = 3;
    shape* sharray[N];

    bowl bw( 20, 0, 3 );
    square sq( 20, 1, 5 );
    cap cp( 30, 1, 7 );

    sharray[0] = &bw;
    sharray[1] = &sq;
    sharray[2] = &cp;

    cout << endl << endl;

    for( int j = 0; j < N; j++ )
        sharray[j]->draw();

    getch();

}

//---------------------------------------------------------------------------
* 다형성을 이용한 해체 - 참조 전달하기 다형성을 사용하면 코드를 특정 클래스와 무관하게 만들 수 있다. 다음을 가정해 보자. main()에 전역(비구성원) func()가 있다고 가정해보자. func()는 각 객체를 취급할때 마다 다른 역할을 하게된다면, 코드가 대단히 복잡해질 것이다. 그러나 참조와 가상함수를 이용하면 하나의 func()로 여러 Class를 동일한 형식으로 취급할 수 있다. 객체가 참조로 함수에 전달되면, 문법은 객체 자체가 전달되는 것처럼 나타나지만, 실제로는 객체 포인터가 대신 전달된다. ( '.' 연산자로 포인터를 다루는 격이다. ) 참조로 전달된 객체는 포인터의 특징을 갖는다. 즉, 포인터는 같은 크기를 갖기때문에 기초 Class의 참조를 기대하는 func()의 인자에 유도 Class의 참조를 넘겨도 무방하다. 또한 func()는 넘어오는 참조인자가 기초 Class인지 유도 Class인지 구별할 필요가없다. 컴파일러는 단지 기초 Class에서 유도되었다는 것만 알뿐이다. C++의 다형성은 가상 함수에 달려 있다.
//---------------------------------------------------------------------------
// 작성일 : 2001.09.25
// 제  목 : 참조로 전달하기(다형성을 이용한 해체)
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

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

class Base
{
public:
    virtual void speak() {
        cout << "\nBase speaks";		
    }
};

/////////////////////////////////////////////////////////////////////////////

class Derv1 : public Base
{
public:
    void speak() {
        cout << "\nDerv1 speaks";
    }
};

/////////////////////////////////////////////////////////////////////////////

class Derv2 : public Base
{
public:
    void speak() {
        cout << "\nDerv2 speaks";
    }
};

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

#pragma argsused
void main()
{

    void func( Base& );
    Derv1 d1;
    Derv2 d2;

    func(d1);
    func(d2);

    getch();

}

void func( Base& obj )
{
    obj.speak();
}

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

(결과)
Derv1 speaks
Derv2 speaks

//---------------------------------------------------------------------------
- 포인터 전달하기 참조는 대체로 객체가 정의를 통해 만들어져 그 이름이 알려져 있을 때 적당하다. 포인터는 객체가 new를 통해 만들어져 그 포인터만 확보되어 있을 때 사용된다. 일반적으로 참조는 포인터보다 더 안전하다. 포인터는 그 주소값을 프로그래머가 실수로 바꿀 수 있는 반면, 참조는 일단 초기화되고 나면 바꿀 수 없다.
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.25
// 제  목 : 포인터로 전달하기(다형성을 이용한 해체)
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

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

class Base
{
public:
    virtual void speak() {
        cout << "\nBase speaks";		
    }
};

/////////////////////////////////////////////////////////////////////////////

class Derv1 : public Base
{
public:
    void speak() {
        cout << "\nDerv1 speaks";
    }
};

/////////////////////////////////////////////////////////////////////////////

class Derv2 : public Base
{
public:
    void speak() {
        cout << "\nDerv2 speaks";
    }
};

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

#pragma argsused
void main()
{

    void func( Base* );
    Derv1 d1;
    Derv2 d2;

    func(&d1);
    func(&d2);

    getch();

}

void func( Base* ptr )
{
    ptr->speak();
}

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

(결과)
Derv1 speaks
Derv2 speaks

//---------------------------------------------------------------------------
- 다형성의 해체 예제
//---------------------------------------------------------------------------]
// 작성일 : 2001.09.25
// 제  목 : person Class 예제 (다형성을 이용한 해체)
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#include 
#pragma hdrstop

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

class person
{
protected:
    char name[40];

public:
    virtual void getData() {
        cout << "    Enter name : ";  cin >> name;
    }
    virtual void putData() {
        cout << "\nName = " << name;
    }
    virtual void isOutStanding() {} // 빈 함수 본문
};

/////////////////////////////////////////////////////////////////////////////

class student : public person
{
private:
    float gpa;          // 성적 평점
public:
    void getData() {
        person::getData();
        cout << "    Enter student's GPA : ";
        cin >> gpa;
    }
    void putData() {
        person::putData();
        cout << "    GPA = " << gpa;
    }
    void isOutStanding() {
        if( gpa > 3.5 )
            cout << " (This person is outstanding)";
    }
};

/////////////////////////////////////////////////////////////////////////////

class teacher : public person       // teacher 클래스
{
private:
    int numPubs;            // 발행된 논문 수
public:
    void getData() {
        person::getData();
        cout << "    Enter number of teacher's publications : ";
        cin >> numPubs;
    }
    void putData() {
        person::putData();
        cout << "    Publications = " << numPubs;
    }
    void isOutStanding() {
        if( numPubs > 100 )
            cout << " (This person is outstanding)";
    }
};

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

#pragma argsused
void main()
{

    person* persPtr[100];           // person 포인터의 목록
    int n = 0;                      // 목록의 사람 수
    char choice;
    int j;

    person* getPerson();            // 기본형
    void displayPerson( person* );

    while( 1 ) {
        cout << endl
             << "'a' to add new person" << endl
             << "'d' to display all persons" << endl
             << "'x' to exit program" << endl
             << "Enter selection : ";

        cin >> choice;
        switch( choice ) {
        case 'a':
            persPtr[n++] = getPerson();
            break;
        case 'd':
            for( j = 0; j < n; j++ )
                displayPerson( persPtr[j] );
            break;
        case 'x':
            for( j = 0; j < n; j++ )
                delete persPtr[j];
            exit(0);
            break;
        default:
            cout << "\nNo such selection";
        } // end of switch
    } // end of while

    getch();

}

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

person* getPerson()
{
    person* tp;
    char choice;

    cout << "Enter person, student or teacher (p/s/t) : ";
    cin >> choice;
    if( choice == 's' )
        tp = new student;
    else if( choice == 't' )
        tp = new teacher;
    else
        tp = new person;

    tp->getData();
    return tp;
}

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

void displayPerson( person* pp )
{
    pp->putData();
    pp->isOutStanding();
}

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

(결과)
'a' to add new person
'd' to display all persons
'x' to exit program
Enter selection : a
    Enter name : Francine
    Enter student's GPA : 3.9
'a' to add new person
'd' to display all persons
'x' to exit program
Enter selection : d

    Name = Francine   GPA = 3.9 (This person is outstanding)

//---------------------------------------------------------------------------
(2) 추상 Class와 가상 파괴자 - 추상 Class 모든 Class의 기초 Class로 지정하고싶을때는 추상 Class로 지정하는 것이 여러가지 오류를 막을 수 있다. 추상 Class란 : 실제 객체가 만들어지지 않는 객체를 의미한다.
    class Base
    {
    public:
        virtual void show()    // 가상 함수
        { cout << "\nError : base version of show()"; }
    };
위와같은 기초 Class는 직접 그린내용을 보여줄 수 없지만 여전히 객체를 만들 수 있다. 추상 기초 Class를 만들면 컴파일러가 모든 Class 사용자들에게 그 Class의 객체를 만들지 못하도록 알려줄 수 있다. 해당하는 Class가 추상이라는 것을 컴파일러에 알려주는 방법은 적어도 Class 내부에 하나의 순가상 함수를 정의하면 된다. 순가상 함수는 본문이 없는 가상 함수로서 기초 Class에서 가상 함수의 본문이 없어지고 함수 선언문에 =0이 추가된다.
    class Base
    {
    public:
        virtual void show() = 0;    // 순가상함수
    };

    class Derv1 : public Base
    {
    public:
        void show()
        { cout << "\nDerv1"; }
    };

    class Derv2 : public Base
    {
    public:
        void show()
        { cout << "\nDerv2"; }
    };

    void main()
    {
        Derv1 dv1;
        Derv2 dv2;

        // Base ba;    // 오류 : 추상 기초 Class는 인스턴스를 만들 수 없다.
    }
- 추상 Class의 사용 순가상 함수를 포함하고 있는 Class의 객체를 만들거나, 그러한 Class의 객체를 값으로 전달하거나 리턴하는 함수 호출은 작성할 수 없다. 하지만, 추상 Class의 객체를 참조 또는 포인터로 전달하기와 리턴하기는 포인터가 실제로 유도 Class 객체를 가리키므로 문제가 없다. 만약 본문이 있는 함수를 순가상 함수로 만들려면 단지 =0만 붙여주면 된다. Ex)
    virtual void getdata() = 0
    {
    ......
    }
순가상 함수를 사용하는 이유는 다형성에서 기초 Class의 불필요한 생성을 막고 좀더 구조화된 코딩을 하기위해서 이다.
//---------------------------------------------------------------------------]
// 작성일 : 2001.10.10
// 제  목 : 추상클래스 Shape 예제
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 
#pragma hdrstop

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

class shape
{
private:
    int xCo, yCo;
    int size;
protected:
    int getx() const { return xCo; }
    int gety() const { return yCo; }
    int getz() const { return size; }
    void down() const;
public:
    shape( int x, int y, int s ) : xCo( x ), yCo( y ), size( s ) {}
    virtual void draw() const = 0;
};

void shape::down() const
{
    for( int y = 0; y < yCo; y++ )
        cout << endl;
}

/////////////////////////////////////////////////////////////////////////////

class square : public shape
{
public:
    square( int x, int y, int s ) : shape( x, y, s ) {}
    void draw() const;
};

void square::draw() const
{
    shape::down();
    for( int y = 0; y < getz(); y++ )
    {
        int x;
        for( x = 1; x < getx(); x++ )
            cout << ' ';
        for( x = 0; x < getz(); x++ )
            cout << 'X';
        cout << endl;
    }
}

/////////////////////////////////////////////////////////////////////////////

class cap : public shape
{
public:
    cap( int x, int y, int s ) : shape( x, y, s ) {}
    void draw() const;
};

void cap::draw() const
{
    shape::down();
    for( int y = 0; y < getz(); y++ )
    {
        int x;
        for( x = 0; x < getx() - y + 1; x++ )
            cout << ' ';
        for( x = 0; x < 2 * y + 1; x++ )
            cout << 'X';
        cout << endl;
    }
}

/////////////////////////////////////////////////////////////////////////////

class bowl : public shape
{
public:
    bowl( int x, int y, int s ) : shape( x, y, s ) {}
    void draw() const;
};

void bowl::draw() const
{
    shape::down();
    for( int y = 0; y < getz(); y++ )
    {
        int x;
        for( x = 0; x < getx() - ( getz() - y ) + 2; x++ )
            cout << ' ';
        for( x = 0; x < 2 * ( getz() - y ) - 1; x++ )
            cout << 'X';
        cout << endl;
    }
}

/////////////////////////////////////////////////////////////////////////////

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

#pragma argsused
void main()
{

    const int N = 3;
    shape* sharray[N] = { &bowl( 10, 0, 3 ),
                          &square( 20, 1, 5 ),
                          ∩( 30, 1, 7 ) };

    cout << sizeof( int* );

    cout << endl << endl;
    for( int j = 0; j < N; j++ )
        sharray[j]->draw();

    getch();

}

//---------------------------------------------------------------------------
- 가상 파괴자 기초 Class의 파괴자를 가상으로 지정하지 않으면 유도 Class의 파괴자는 호출되지 않고 언제나 기초 Class의 파괴자가 호출된다. Ex)
    class Base
    {
    public:
        virtual ~Base() = 0
        { cout << "\nBase destructor"; }
    };

    class Derv : public Base
    {
    public:
        ~Derv()
        { cout << "\nDerv destructor"; }
    };

    void main()
    {
        Base* pb = new Derv;
        delete pb;
        cout << "\nProgram terminates";
    }

    이론적 결과
    Derv Destructor
    Base Destructor
    Program terminates
아쉽게도 코드가 있는 순가상함수는 컴파일 되지않았다. (3) RTTI (RunTime Type Identification) 실행시간에 데이타 타입을 구별할 수 있는 방법을 의미한다. typeinfo.h파일을 인클루드하고 typeid()함수로 기본형은 물론이고 Class 들을 상호 비교해서 구별할 수 있다.
//---------------------------------------------------------------------------]
// 작성일 : 2001.10.10
// 제  목 : RTTI (실시간 형식별) 예제
// 작성자 : 남병철
//---------------------------------------------------------------------------
#include 
#include 
#include 
#pragma hdrstop

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

class ClassA {};

class ClassB {};

void main()
{
    ClassA ObjA;
    ClassB ObjB;

    if( typeid( ObjA ) == typeid( ClassA ) )
        cout << "\nObjA is an object of ClassA";
    else
        cout << "\nObjA is not a member of ClassA";

    if( typeid( ObjB ) == typeid( ClassA ) )
        cout << "\nObjB is an object of ClassA";
    else
        cout << "\nObjB is not an object of ClassA";

    getch();
}

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

(결과)
ObjA is an object of ClassA
ObjB is not an object of ClassA

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

+ -

관련 글 리스트
35 (06) Virtual, Friend in C++ (1) 남병철.레조 11319 2009/06/21
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.