C++/기초를 탄탄히 세워주는 C++ 프로그래밍 입문(황준하 저)

기초를 탄탄히 세워주는 C++ 프로그래밍 입문 9장 연습문제

꾸준함. 2017. 7. 6. 11:00

[9.1]

/*

그림 9.1과 같은 클래스 구성에 있어서 클래스 객체들 간의 복사 생성이 수행되는지

테스트해보도록 한다. 다음과 같은 코드가 수행 가능한지 생각해보면 된다

*/

#include <iostream>

using namespace std;

 

#define PI 3.14

 

class CPoint //임의로 추가한 CPoint 객체

{

private:

        int x;

        int y;

public:

        CPoint(int a = 0, int b = 0) :x(a), y(b)

        {

        }

        CPoint &operator=(const CPoint &Po)

        {

               cout << "CPoint 대입 연산자" << endl;

               x = Po.x;

               y = Po.y;

               return (*this);

        }

};

 

class CCircle

{

protected:

        int x, y;

        double Radius;

public:

        CCircle(int a, int b, double r) :x(a), y(b), Radius(r)

        {

        }

        double GetArea()

        {

               return (PI*Radius*Radius);

        }

        CCircle &operator=(const CCircle &Cir)

        {

               cout << "CCircle 대입 연산자" << endl;

               x = Cir.x;

               y = Cir.y;

               Radius = Cir.Radius;

        }

};

 

class CSphere:public CCircle

{

private:

        int z;

public:

        CSphere(int a, int b, int c, double r) :CCircle(a, b, r), z(c)

        {

        }

        CSphere &operator=(const CSphere &Sph)

        {

               cout << "CSphere 대입 연산자" << endl;

               z = Sph.z;

               CCircle::operator=(Sph);

        }

        double GetArea()

        {

               return (4 * PI*Radius*Radius);

        }

        double GetVolume()

        {

               return ((4.0 / 3.0)*PI*Radius*Radius*Radius);

        }

};

 

int main(void)

{

        CPoint Po(1, 1);

        CCircle Cir(2, 2, 2);

        CSphere Sph(3, 3, 3, 3);

 

        //CPoint Po2 = Cir; //무관한 클래스 객체 간 복사 생성(x)

        CCircle Cir2 = Sph; //derived로부터 base 객체의 복사 생성(O)

        //CSphere Sph2 = Cir; //base로부터 derived 객체의 복사 생성(x)

        return 0;

}

 

[9.2]

/*

연습문제 9.1에서 7라인은 수행되지 않는다.

서로 무관한 클래스 객체 사이의 복사 생성 또는 대입은 기본적으로 허용되지 않기 때문이다.

그러나 이것이 가능하도록 만들 수는 있다.

CCircle 객체로부터 CPoint 객체를 복사 생성할 수 있도록 만들고 또한 CCircle 객체를 CPoint 객체로 대입할 수 있도록 만들어본다.

대입 연산자 오버로딩과 복사 생성자만 잘 이용하면 쉽게 해결할 수 있을 것이다.

대입 또는 복사 생성의 의미는 각자 알아서 부여하도록 한다.

*/

#include <iostream>

using namespace std;

 

#define PI 3.14

 

class CPoint; //미리 명시

 

class CCircle

{

protected:

        int x, y;

        double Radius;

public:

        CCircle(int a, int b, double r) :x(a), y(b), Radius(r)

        {

        }

        CCircle(const CCircle &cir)

        {

               x = cir.x;

               y = cir.y;

        }

        double GetArea()

        {

               return (PI*Radius*Radius);

        }

        double GetRadius() const

        {

               return Radius;

        }

        int GetX() const

        {

               return x;

        }

        int GetY() const

        {

               return y;

        }

        CCircle &operator=(const CCircle &Cir)

        {

               cout << "CCircle 대입 연산자" << endl;

               x = Cir.x;

               y = Cir.y;

               Radius = Cir.Radius;

        }

        void Print()

        {

               cout << "(" << x << ", " << y << ")" << endl;

               cout << "반지름: " << Radius << endl;

        }

};

 

class CPoint

{

private:

        int x;

        int y;

public:

        CPoint(int a = 0, int b = 0) :x(a), y(b)

        {

        }

        CPoint &operator=(const CCircle &cir)

        {

               x = cir.GetX();

               y = cir.GetY();

               return *this;

        }

        CPoint(CCircle &cir)

        {

               x = cir.GetX();

               y = cir.GetY();

        }

        int GetX()

        {

               return x;

        }

        int GetY()

        {

               return y;

        }

        void Print()

        {

               cout << "(" << x << ", " << y << ")" << endl;;

        }

};

 

int main(void)

{

        CPoint Po(1, 1);

        cout << "대입 전: ";

        Po.Print();

        CCircle Cir(3, 3, 3);

 

        cout << "대입 후: ";

        CPoint Po2 = Cir;

        Po2.Print();

        return 0;

}

 


[9.3]

/*

그림 9.4와 같은 클래스들이 존재한다.

다음 중 가능한 대입은 어느 것인가?

*/

#include <iostream>

using namespace std;

 

class A

{

public:

        A()

        {

               cout << "A 생성자" << endl;

        }

};

 

class B :public A

{

public:

        B()

        {

               cout << "B 생성자" << endl;

        }

};

 

class C :public B

{

public:

        C()

        {

               cout << "C 생성자" << endl;

        }

};

 

int main(void)

{

        A objA;

        C objC;

 

        A *pA = &objC; //base 클래스가 derived 클래스를 대입하는 것은 가능

        //C *pC = &objA; //반대로 derived 클래스가 base 클래스를 대입하는 것은 불가능

        return 0;

}


[9.4]

/*

다음 프로그램의 출력 결과는 무엇인가?

*/

#include <iostream>

using namespace std;

 

class B

{

public:

        B()

        {

        }

        virtual void p()

        {

               cout << "B::p()" << endl;

        }

        void q()

        {

               cout << "B::q()" << endl;

        }

};

 

class D :public B

{

public:

        D()

        {

        }

        virtual void p()

        {

               cout << "D::p()" << endl;

        }

        void q()

        {

               cout << "D::q()" << endl;

        }

};

 

int main(void)

{

        B b;

        D d;

        B *pb = new B;

        B *pd = new D;

        D *pd2 = new D;

 

        b.p();

        b.q();

        d.p();

        d.q();

        pb->p();

        pb->q();

        pd->p(); //virtual이기 때문에 class D p()

        pd->q();

        pd2->p();

        pd2->q();

 

        return 0;

}

 


[9.5]

/*

다음 프로그램의 가상 함수 테이블을 비롯한 메모리 구조를 그려 본다.

base 클래스와 derived 클래스는 에제 9.7과 동일하다

*/

#include <iostream>

using namespace std;

 

class base

{

private:

        int x;

public:

        void func1()

        {

               cout << "base::func1" << endl;

        }

        virtual void func2()

        {

               cout << "base::func2" << endl;

        }

        virtual void func3()

        {

               cout << "base::func3" << endl;

        }

};

 

class derived :public base

{

private:

        int y;

public:

        void func1()

        {

               cout << "derived::func1" << endl;

        }

        void func2()

        {

               cout << "derived::func2" << endl;

        }

        void func4()

        {

               cout << "derived::func4" << endl;

        }

};

 

int main(void)

{

        base Base[2];

        derived Derived[2];

        base *pBase;

        int i, j;

 

        for (i = 0; i < 2; i++)

        {

               for (j = 0; j < 2; j++)

               {

                       if (i == 0)

                              pBase = &Base[j];

                       else

                              pBase = &Derived[j];

 

                       pBase->func1();

                       pBase->func2();

                       pBase->func3();

               }

        }

        return 0;

}

 


[9.6]

/*

예제 9.9에서 CShape 클래스를 추상 클래스로 만들어 본다.

그리고 CShape, CCircle, CRect 클래 모두 객체의 면적을 출력하기 위한 Print 함수를 추가한다.

이 때 CShape 클래스의 경우 Print 함수를 순수 가상함수로 선언한다.

마지막으로 CShape 클래스에 출력 연산자 (<<) 오버로딩을 추가한다

*/

#include <iostream>

using namespace std;

 

class CShape

{

protected:

        int x, y;

public:

        CShape(int a, int b) :x(a), y(b)

        {

        }

        void Move(int a, int b)

        {

               x += a;

               y += b;

        }

        virtual void Print() = 0;//순수 가상 함수

        friend ostream &operator<<(ostream &out, CShape &Sh);

};

 

ostream &operator<<(ostream &out, CShape &Sh) //<< 오버로딩

{

        Sh.Print();

        return out;

}

 

class CCircle :public CShape

{

private:

        double Radius;

public:

        CCircle(int a, int b, double r) :CShape(a, b), Radius(r)

        {

        }

        virtual double GetArea()

        {

               return (3.14*Radius*Radius);

        }

        void Print()

        {

               cout << "원의 면적: " << GetArea() << endl;

        }

};

 

class CRect :public CShape

{

private:

        int Garo, Sero;

public:

        CRect(int a, int b, int g, int s) :CShape(a, b), Garo(g), Sero(s)

        {

        }

        double GetArea()

        {

               return (Garo*Sero);

        }

        void Print()

        {

               cout << "사각형의 면적: " << GetArea() << endl;

        }

};

 

int main(void)

{

        CCircle Cir(1, 1, 1);

        CRect Rect(2, 2, 2, 2);

        CShape *pSpe;

 

        pSpe = &Cir;

        cout << *pSpe;

 

        pSpe = &Rect;

        cout << *pSpe;

        return 0;

}


[9.7]

/*

다음 프로그램의 출력 결과는 무엇인가?>

*/

#include <iostream>

using namespace std;

 

class Base

{

public:

        Base()

        {

               cout << "Base::Base()" << endl;

        }

        Base(int n)

        {

               cout << "Base::Base(" << n << ")" << endl;

        }

};

 

class Derived :public Base

{

private:

        Base b;

public:

        Derived()

        {

               cout << "D::D()" << endl;

        }

        Derived(int n) :Base(n)

        {

               Base btemp(-n);

               b = btemp;

               cout << "Derived::Derived(" << n << ")" << endl;

        }

};

 

int main(void)

{

        Derived d(3); //Base 클래스가 먼저 생성되고 Derived 클래스가 생성되는 과정에서 디폴트 Base 클래스 생성자가 호출된 다음에(상속을 받았으므로)

        //Base(-3) 클래스가 생성되고 Derived(3) 클래스가 생성된다

 

        return 0;

}

 



개발 환경:Visual Studio 2017


지적, 조언, 질문 환영입니다! 댓글 남겨주세요~


[참고] 기초를 탄탄히 세워주는 C++ 프로그래밍 입문 황준하 저

반응형