언어 자료구조 알고리즘/Escort C++

[C++] 개체 출력자

언제나휴일 2016. 4. 15. 15:14
반응형

7.3 개체 출력자

 

 C++ 표준 기구에서는 iostream은 프로그램의 데이터를 출력 스트림에 보내거나 입력 스트림으로부터 데이터를 얻어오기 위한 목적으로 제공하고 있습니다. 여기에서는 우리가 정의하는 형식 개체에 대해서도 출력 스트림인 ostream을 통해 내보내는 방법에 대해 먼저 얘기를 해 보도록 합시다.

 

 개체의 정보를 다른 매체로 내보내는 도구를 개체 출력자라 합니다. 여기에서는 ostream을 통해 개체의 정보를 다른 매체로 내보내기 위한 방법을 살펴볼 것입니다. 우리는 이미 cout이라는 ostream 기반의 개체와 << 연산자를 통해 여러 기본 형식들을 화면에 출력하고 있습니다. 이는 ostream 클래스 내부에서 다양한 기본 형식에 대해 << 연산자 중복 정의가 되어 있기 때문입니다.

 

LikeAsOStream.h

#pragma once

#include <stdio.h>

extern const char *Endl;

class LikeAsOStream

{

public:

    LikeAsOStream &operator<<(int val);

    LikeAsOStream &operator<<(char val);

    LikeAsOStream &operator<<(const char *val);

    LikeAsOStream &operator<<(float val);

};

 

  

LikeAsOStream.cpp

#include "LikeAsOStream.h"

const char *Endl="\n";

LikeAsOStream &LikeAsOStream::operator<<(int val)

{

    printf("%d",val);

    return (*this);

}

LikeAsOStream &LikeAsOStream::operator<<(char val)

{

    printf("%c",val);

    return (*this);

}

LikeAsOStream &LikeAsOStream::operator<<(const char *val)

{

    printf("%s",val);

    return (*this);

}

LikeAsOStream &LikeAsOStream::operator<<(float val)

{

    printf("%f",val);

    return (*this);

}

 

 이와 비슷한 형태로 ostream클래스에는 << 연산자 중복 정의가 되어 있어 printf 함수를 사용할 때 어떠한 형식을 출력하기를 원하는지를 명시하지 않아도 컴파일러가 적절한 함수 호출로 연결하여 [그림 7.11]과 같이 출력할 수 있는 것입니다.


[그림 7.11]

  

 또한, ostream 클래스는 ofstream의 기반 클래스이며 파일 스트림에 출력을 할 때도 cout을 통해 화면에 출력하는 것과 같은 방식으로 가능합니다.

 

Example.cpp

#include <fstream>

using namespace std;

 

void main()

{

    ofstream of("data.txt");

    of<<"번호:"<<3<<" 이름:"<<"홍길동"<<endl;

    of.close();

}

 

  우리는 여기에서 출력 스트림이 화면에 출력하기 위한 개체이든 파일에 출력하기 위한 개체이든 상관없이 사용자가 정의한 클래스 형식도 출력할 수 있게 해 봅시다.

 

 이를 위해서는 ostream 형식과 우리가 출력하고자 하는 형식을 입력 인자로 받는 << 연산자를 중복 정의해야 할 것입니다. 그리고 ostream C++ 언어의 형식이 아니고 C++ 표준 기구에서 제공하는 사용자 정의 형식이기 때문에 우리가 출력하고자 하는 형식이 Stu *와 같은 경우도 연산자 중복 정의가 가능합니다. 주의해야 할 것 중 하나가 << 연산을 하였을 때 반환 형식인데 cout<<num<<name<<endl; 과 같이 연쇄 작업이 가능하게 하기 위해서는 ostream &를 반환하도록 정의해야 합니다. 그리고 ostream은 이미 정의되어 있기 때문에 우리는 전역에 연산자 중복 정의를 해야 합니다. 우리가 전역에 연산자 중복 정의를 통해 출력할 형식은 기본 형식이 아닌 사용자 정의 형식 혹은 사용자 정의 형식의 포인터가 참조하는 개체일 것입니다. 이 경우 전역에 정의한 연산자 중복 정의 함수에서 개체의 private으로 접근 지정된 멤버에 접근하는 것이 불가능합니다. 이 경우 friend로 등록함으로써 private으로 지정된 멤버에 접근을 허용하는 것은 정보 은닉성을 파괴하는 것일까요? 아마도 해당 연산자 중복 정의를 위한 전역 함수에 대한 정의를 클래스 내부에 하는 것이 타당하나 개체의 정보를 출력할 때 << 연산자의 좌항에 ostream 개체가 오기 때문에 ostream 클래스 내부에 << 연산자를 중복 정의를 해야 합니다. 하지만, ostream 클래스는 우리가 정의한 것이 아니기 때문에 전역에서 연산자 중복 정의를 할 수 밖에 없는 것이죠. 이 경우 해당 전역 함수를 우리가 정의하는 클래스의 접근 권한이 private으로 설정한 멤버에 접근한다고 해서 정보 은닉성이 떨어지는 것은 아닐 것입니다.


 friend 로 지정된 전역 함수를 Stu 클래스 내부에 정의하는 방식으로 개체 출력자를 정의해 봅시다. 예제와 같이 friend로 지정된 함수가 클래스 내부에 정의되어 있어도 이는 클래스의 멤버가 아닙니다.

 

Example.cpp

#pragma once

#include <iostream>

#include <string>

using namespace std;

class Stu

{

    const int num;

    string name;

public:

    Stu(int _num,string _name):num(_num)

    {

        name = _name;

    }

    friend ostream &operator << (ostream &os,const Stu *stu)

    {

        os<<(*stu);

        return os;

    }

    friend ostream &operator << (ostream &os,const Stu &stu)

    {

        os<<"번호:"<<stu.num<<" 이름"<<stu.name<<endl;

        return os;

    }

};

void main()

{

    Stu *stu = new Stu(3,"홍길동");

    cout<<stu;

    delete stu;

    Stu stu2(4,"강감찬");

    cout<<stu2;

}

 

7장 산자 의 Part1

7장 산자 의 Part2

(모든 동영상 강의는 무료입니다.)

반응형