프로그래밍 방법론 학기말고사 (2008년 12월 3일)

1. 다음 C++ 프로그램들의 출력을 쓰시오 (20).

(a)

class A { public: virtual void foo() { cout << "A_foo()" << endl;}};

class B: public A { public: virtual void foo() { cout << "B_foo()" << endl;}};

int main () {

A a, *a1;

B b, *b1;

a = b; a.foo();

a1 = &b; a1->foo();

A& a2 = b; a2.foo();

cout << "-------" << endl;

b1 = static_cast< B * > (&a); b1->foo();

B& b2 = static_cast< B & > (a); b2.foo();

cout << "-------" << endl;

(static_cast< A & > (b)).foo();

(static_cast< A   > (b)).foo();

}

(b)

class Y; // just for avoiding compilation error

class X {

public:

X() { }

X(X& x) { cout << "X::copy constructor_X"  << endl; }

X(Y& y) { cout << "X::copy constructor_Y"  << endl; }

X& operator = (const X& x) { cout << "X::operator=X" << endl; return *this;}

X& operator = (const Y& y) { cout << "X::operator=Y" << endl; return *this;}

};

class Y: public X {

public:

Y() { }

Y(Y& y) { cout << "Y::copy constructor_Y"  << endl; }

Y& operator = (const Y& y) { cout << "Y::operator=Y" << endl; return *this;}

};

main() {

X x1, x2(x1), *xp;

cout << "---" << endl;

Y y1, y2=y1, *yp;

cout << "---" << endl;

yp = new Y();

xp = yp;

cout << "---" << endl;

*xp = *yp;

cout << "---" << endl;

X& xref = x1;

Y& yref = *yp;

cout << "---" << endl;

xref = yref = y1;

}

2. (a) 다음 C++ 프로그램의 출력을 쓰시오 (15).

class A { public: A()                    {cout << "const for A" << endl;};    //(a)

A (A& a)              {cout << "copy for A" << endl;} };   //(b)

class B:  public A { public: B()       {cout << "const for B" << endl;};    //(c)

B (B& b) { cout << "copy for B" << endl; } }; //(d)

class C { public: C()                    {cout << "const for C" << endl;};    //(e)

C (C& c)               {cout << "copy for C" << endl;}      //(f)

private: B b; };                                                          //(g)

int main () {

C c1;

cout << "----" << endl;

C c2(c1);}                      // <---(h)

(b) 위 프로그램의 (h)에서 모든 클래스의 copy constructor가 호출되었는가? 그렇다면 어떻게 호출되었는지 설명하시오. 아니라면 호출되도록 (a)~(g)중 해당 줄(들)을 수정하시오.

3. 다음 프로그램을 컴파일하여 수행하려고 한다 (25).

(a) 이 프로그램은 제대로 컴파일되지 않는다. 그 이유를 간단히 설명하고 컴파일이 되기 위해서는 왼쪽의 String과 Substring 클래스를 어떻게 “최소한”으로 수정해야 하는 지 설명하시오 (store_strings()와 main()은 수정불가). 단 store_strings()의 수행이 끝났을 때 sp가 가리키는 object의 strp는 "Hello"를 point하고 substrp는 “ello"를 가리켜야 한다.

(b) 위의 (a)에서 수정된 프로그램의 출력을 쓰시오.

(c) 위의 (a)에서 수정된 프로그램을 실행하여 수행이 끝났을 때 할당 받았던 메모리는 모두 반납되는가? 아니라면 그 이유를 설명하고 이를 해결하기 위해 (a)의 String과 Substring 클래스를 어떻게 수정해야 하는 지 설명하시오.

(d) 함수 store_strings() 선언에서 String &sp 대신 String sp 를 사용한다면 출력이 어떻게 달라지겠는가? 그 이유를 간단히 설명하시오.

class String {                                     void store_strings (String &sp,

public:                                                     char *strp,char *substrp) {

String () {strp=0; }                                 sp.save_string (strp);

void save_string (char *cp) {                      sp.save_substring (substrp);

strp = new char [strlen(cp)+1];                 sp.print_string();

strcpy (strp, cp);                                sp.print_substring();

}                                                  }

void print_string()

{if (strp) cout<< strp<< endl;}

~String() { if(strp) delete [] strp; }      main() {

private:                                             String *sp;

char *strp;                                        char *sbuf = "Hello";

};                                                      char *subsbuf = "ello";

class Substring : public String {

public:                                              sp = new Substring;

Substring() {substrp=0; }                       store_strings(*sp,sbuf,subsbuf);

void save_substring (char *cp) {               cout << "---" << endl;

substrp = new char [strlen(cp)+1];           sp->print_string();

strcpy (substrp, cp);                          sp->print_substring();

}                                                    delete sp;

void print_substring() { print_string();     }

if(substrp) cout << substrp << endl;}

~Substring(){if(substrp)delete[] substrp;}

private:

char *substrp;

};

4. 다음의 (a)~(i) 중에서 컴파일 에러가 발생하는 곳(들)은 어디인가? (5)

class X { private  :  int i;  protected:  int j;   public   :  int k; };

class Y : protected X {  public: void  print () {

cout << i << endl;  // (a) LEGAL?

cout << j << endl;  // (b) LEGAL?

cout << k << endl;  // (c) LEGAL?

}

};

main() {

X x;

Y y;

cout << x.i << endl;  // (d) LEGAL?

cout << x.j << endl;  // (e) LEGAL?

cout << x.k << endl;  // (f) LEGAL?

cout << y.i << endl;  // (g) LEGAL?

cout << y.j << endl;  // (h) LEGAL?

cout << y.k << endl;  // (i) LEGAL?

}

5. 다음은 복소수 클래스의 일부이다. (20)

class Complex {

public:

Complex( double r = 0.0, double i=0.0 ): real(r), imaginary(i) { };

Complex operator+(Complex c0, const Complex& c1)

{ return Complex (c0.real+c1.real, c0.imaginary+c1.imaginary);};

const Complex operator=( const Complex& c)

{ return Complex(c.real, c.imaginary);};

void print() { cout << '(' << real << ", " << imaginary << ")";}

private:

double real, imaginary;

};

main() {

Complex x, y(4.3, 8.2), z;

x = y;

z = x + y;

x.print();

}

(a) 위 Complex 클래스에서 잘못된 부분(들)을 지적하고 수정하시오.

(b) print() 대신 사용하기위해 overload된 << operator 함수를 추가하려고 한다. 이 함수의 클래스 내부에서의 prototype을 보이고 그 함수를 작성하시오.

(c) 어떤 Complex 변수 x에 대해 x++ 라는 operator를 정의하여 real과 imaginary 값을 각각 1.0 씩 증가되도록 하고자 한다. 이를 member function으로 정의하시오.

6. 다음 각각에 대하여 간단히 설명하시오. 길거나 불필요한 내용이 있으면 감점 (15).

(a) 어떤 클래스에 destructor를 정의해야하는 경우 copy constructor와 overload된 assignment(=) operator도 아울러 정의하는 것을 권장하고 있다. 그 이유는 무엇인가?

(b) Virtual function call을 많이 사용하면 성능에 어떤 영향을 주는가? 그 이유는?

(c) 어떤 클래스를 정의할 때 이를 template class로 정의하는 경우는 언제인가?