차근차근/C

C 사용자를 위한 C++

예쁜꽃이피었으면 2014. 7. 29. 01:03

http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/C%2B%2B/Documents/CPP_Programing_for_Cprogramer#AEN24

 

윤 상배

dreamyun@yahoo.co.kr 



1절. C프로그래머를 위한 C++

1.1절. 새로운 include 방법

C++ 에서는 헤더파일을 인클루드 시키기 위해서 새로운 방법을 사용한다. C++ 에서는 C의 표준 헤더파일을 인클루드 시키기 위해서 ".h" 확장자를 사용하는 대신에 ".h"를 생략하고 헤더파일의 가장앞에 "c" 를 붙여서 인클루드 시킨다. 제대로된 인클루드를 위해서 "using namespace std;" 를 포함시키도록 한다. 표준 C++ 헤더는 확장자를 생략하면 된다 - 생략하지 않아도 문제는 없지만 -.

물론 기존의 C 스타일대로 헤더파일을 인클루드 시켜도 문제는 없다. 그러나 어떤 컴파일러의 경우(gcc 3.x 와 같은) 디버깅 옵션을 켜놓은 상태에서 컴파일할경우 warning 메시지를 출력하기도 한다.

// stdlib.h -> cstdlib
#include <cstdlib>
#include <iostream>

using namespace std;
int main()
{
    char *age = "25";

    cout << atoi(age) << endl;
}
   

 


1.2절. 라인단위 주석사용

C 에서와 마찬가지로 // 를 이용한 라인단위 주석의 사용이 가능하다.

#include <cstdlib>
#include <iostream>             // iostream 라이브러리 사용

using namespace std;           // 표준 라이브러리 namespace 지정
int main()
{
    char *age = "25";

    cout << atoi(age) >> endl; // 출력
    return 1;                  // 종료
}
   

 


1.3절. 간단하게 사용할수 있는 입출력 스트림

C 에서는 간단한 화면/키보드 입출력이라도 꽤 번거로운 과정을 거쳐야 하지만, C++ 에서는 cout <<, cin >> 을 이용해서 간단한 입출력을 쉽게 처리할수 있다.

#include <iostream>

using namespace std;
int main()
{
    int age;
    char name[32];
    cout << "hello world " << endl;
    cout << "your age : ";
    cin >> age;
    cout << "your name : ";
    cin >> name;

    cout << "Your input is " << name << ":" << age << endl;
}
   

 


1.4절. 변수선언 위치제한

C 의 경우 변수 선언은 함수의 가장첫부분에서 이루어져야 한다. 만약 중간에 선언이 이루어진다면, 컴파일시 에러를 발생하게 된다.

C++ 은 어느 위치에서라도 선언해서 사용할수 있다. 이러한 점이 때로는 코드를 난잡하게 만들기도 하지만, 오히려 코드를 보기쉽게 만들어줄때도 있다.

#include <iostream>

using namespace std;
int main()
{
    int a, b;

    cout << "A : " ;
    cin >> a ;
    cout << "B : " ;
    cin >> b ;

    int sum;
    sum = a + b;
    cout << a << "+" << b << "=" << sum << endl;
}
   

 


1.5절. 전역변수와 지역변수의 동일이름 사용

C 에서는 전역변수와 지역변수가 이름이 같을경우 무조건 지역변수의 값만을 사용할수 있었으나(전역변수 값은 사용 할수가 없다), C++ 에서는 각각 구분해서 사용가능하다.

#include <iostream>
using namespace std;

int my_age = 28;
int main()
{
    int my_age = 35;

    cout << "Local my_age " << my_age << endl;
    cout << "global my_age " << ::my_age << endl;

    return 0;
}
   

 


1.6절. 변수의 상호참조가능

다음과 같은 방법으로 하나의 변수를 다른변수에서 참조하여 사용하는게 가능하다.

#include <iostream>
using namespace std;

int main()
{   
    int a = 200;
    int &b = a;

    b = 100;
    
    cout << "a is "  << a << endl;
    return 0;
}
   
위의 코드를 실행시키면 100 이 출력된다.

 


1.7절. namespace 의 선언

namespace 를 이용해서 변수의 선언이 가능하며 :: 연산자를 통해서 선언 없이 곧바로 변수의 이용이 가능하다.

#include <iostream>
using namespace std;

namespace first
{
    int a;
    int b;
}
namespace second
{
    int a;
    int b;
}
int main()
{
    first::a = 100;
    first::b = 200;

    second::a = 400;
    second::b = 800;

    cout << first::a + second::a << endl;
    cout << first::b + second::b << endl;
}
   

 


1.8절. inline 함수의 사용

간단한 함수들은 inline 으로 선언해서 사용함으로써 몇가지 잇점을 얻을수 있다. inline 으로 선언된 함수는 일종의 macro 와 같이 작동을 하게 된다. 즉 필요할때 불러오는 방식이 아니라, 코드에 바로 insert 된 효과를 준다. 이것이 주는 잇점은 코드가 약간 커지긴 하겠지만, 빠른 실행 속도를 보장해 준다는 점이다.

#include <iostream>
#include <cmath>
using namespace std;

inline double mysqrt(double a, double b)
{
    return sqrt (a * a + b * b);
}
int main()
{
    double k = 6, m = 9;

    // 밑의 2개의 라인은 실행시에 완전히 
    // 동일하게 작동한다.  
    cout << mysqrt(k, m) << endl;
    cout << sqrt(k*k + m*m) << endl;

    return 0;
}
   
inline 인것과 아닌것의 차이를 비교해보고 싶다면, g++ -S 를 이용해서 어셈코드를 얻은다음에 직접 비교 해보기 바란다.

 


1.9절. 예외처리

당신이 C에서 사용하고 있다면, for, if, do, while, switch 와 같은 키워드들를 알고 있을것이다. C++ 에서는 예외처리(EXECPTION)와 관련된 또다른 키워드들을 제공한다. 선택문 혹은 예외처리를 위한 좀더 직관적이고 손쉬운 프로그래밍 작업을 가능하도록 도와준다.

#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    int age;
    char *no_vote[] = {"없습니다", "있습니다."};

    cout << "당신의 나이는 ? ";
    cin >> age;

    try
    {
        if (age > 18) throw 1;
        else throw 0;
    }
    catch(int result)
    {
        cout << "당신은 투표권이 " <<  no_vote[result] << endl;
    }

    return 0;
}
   

 


1.10절. default 인자사용 가능

함수의 인자를 사용할때 기본 인자를 설정할수 있다.

  
#include <iostream>
using namespace std;

int mysqrt(int a, int b = 2)
{
    int c = 1;
    for (int i =0; i < b; i++)
    {
        c *= a;
    }
    return c;
}
int main()
{
    cout << mysqrt(5) << endl;
    cout << mysqrt(5, 5) << endl;
}
   

 


1.11절. Parameters Overload

C++ 의 중요한 잇점중에 하나가 인자를 통한 함수 오버로드가 가능하다는 점이다. 오버로드 기능을 이용함으로써, 서로 다른 연산을 수행하는 함수를 하나의 이름으로 관리 가능 하도록 도와주며, 이는 코드의 유지/보수/가독성을 높여준다.

#include <iostream>

using namespace std;

double add (double a, double b)
{
    return a+b;
}

int add (int a, int b)
{
    return a+b;
}

int main()
{
    cout << add(1, 2) << endl;
    cout << add(1.2, 2.4) << endl;
}
   

 


1.12절. Operator overload

함수인자를 통한 오버로드 뿐만 아니라, 기본적인 연산자들의 오버로드역시 가능하다. 다시 말해서 연산자의 정의를 다시 내릴수 있도록 한다.

#include <iostream>

using namespace std;
struct vector
{
    double x;
    double y;
};

vector operator * (double a, vector b)
{
    vector r;
    r.x = a * b.x;
    r.y = a * b.y;

    return r;
};

int main()
{
    vector k, m;
    k.x = 2;
    k.y = 4;

    m = 3.141927 * k;
    cout << "(" << m.x << "," << m.y << ")" << endl;

    return 0;
}
   
연산자 오버로는 사칙연산자 외에도 +=, ++, [], (), << 등을 포함한 약 40개 이상의 연산자에 대해서도 가능하다.
#include <iostream>

using namespace std;
struct vector
{
    double x;
    double y;
};

ostream& operator << (ostream & o, vector a)
{
    o << "(" << a.x << "," << a.y << ")" ;
    return o;
}

int main()
{
    vector k;
    k.x = 2;
    k.y = 4;

    cout << k << endl;
    cout << "hello "<< endl;

    return 0;
}
   

 


1.13절. template

함수 오버로딩이 꽤 편하긴 하지만, 몇가지 불편함이 있다. 즉 인자의 갯수만큼의 함수를 만들어줘야 한다. 만약 int, float, double 연산을 위한 오버로드된 함수를 만들고자 한다면, 거의 똑같은 3개의 함수를 정의해야만 한다. template 를 사용하면 인자의 자료형에 관계없이 사용가능한 (범용한) 함수의 제작이 가능하다.

#include <iostream>

using namespace std;

template <class T>
T mymin (T a, T b)
{
    T r;
    r = a;

    if (b < a) r = b;

    return r;
}

int main()
{
    cout << "Litle is : " << mymin(2, 100) << endl;
    cout << "Litle is : " << mymin(2.6, 2.4) << endl;
}
   

 

위의 템플릿을 이용한 코드는 꽤 괜찮게 작동하긴 하지만, 한가지 문제가 있다. 위의 코드는 인자의 타입이 동일해야 한다. 만약 인자가 각각 int, double 타입을 가진다면, 컴파일시 에러를 발생시킬것이다. 이문제는 템플릿을 선언할때 서로 다른 인자를 받아들일수 있도록 선언하면 된다.

#include <iostream>

using namespace std;

template <class T1, class T2>
T1 mymin (T1 a, T2 b)
{
    T1 r, converted;

    r = a;

    converted = (T1) b;

    if (converted < a) r =  converted;

    return r;
}

int main()
{
    cout << "Litle is : " << mymin(2, 100) << endl;
    cout << "Litle is : " << mymin(2.6, 2.4) << endl;
    cout << "Litle is : " << mymin(3.4, 3) << endl;
}
   
그외에도 비교연산을 제대로 수행하기 위한 형변환이 필요할 것이다.

 


<ins style="BORDER-TOP: medium none; HEIGHT: 60px; BORDER-RIGHT: medium none; BORDER-BOTTOM: medium none; POSITION: relative; PADDING-BOTTOM: 0px; PADDING-TOP: 0px; PADDING-LEFT: 0px; MARGIN: 0px; BORDER-LEFT: medium none; DISPLAY: inline-table; PADDING-RIGHT: 0px; VISIBILITY: visible; WIDTH: 468px; BACKGROUND-COLOR: transparent"><iframe id="aswift_1" style="POSITION: absolute; LEFT: 0px; TOP: 0px" height="60" marginheight="0" frameborder="0" width="468" allowtransparency="allowTransparency" name="aswift_1" marginwidth="0" scrolling="no" allowfullscreen="true"></iframe></ins>

1.14절. 메모리 할당/해제

메모리 할당과 해제를 위해서 new 와 delete 키워드를 사용할수 있다. 이들은 C 에서 사용하는 malloc, free 대신 사용할수 있다. 만약 배열의 할당을 원한다면 new[] delete[] 를 사용하면 된다.

#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    int *d;

    // int 형을 포함할수 있는 새로운 메모리 공간확보하고 
    // 주소를 되돌려준다. 
    d = new int;
    *d = 21;

    cout << "Type a number : ";
    cin >> *d;
    cout << *d + 5 << endl;

    // 할당받은 메모리 영역을 해제한다.
    delete d;

    // 15개의 int 형자료를 저장할수 있는 새로운 메모리 
    // 공간을 확보하고, 주소를 되돌려준다. 
    d = new int[15];
    d[0] = 1234;
    d[1] = d[0] + 1234;

    cout << d[0] << ":"<< d[1] << ":" << d[2] << endl;
    delete []d;
    return 0;
}
   

 


1.15절. Class

간단히 생각해서 Class 란 발전된 형태의 struct 이다. 데이타와 함께, 데이타를 가공할 METHODS 가 선언될수 있다. 다음은 Class 설명을 위한 간단한 예제이다.

#include <iostream>
#include <cstring>

using namespace std;

class vector
{
    public:
        double x;
        double y;

    inline double surface()
    {
        double s;
        s = x*y;
        if (s < 0)
            s = -s;
        return s;
    }
};

int main()
{
    vector a;
    a.x = 3;
    a.y = 4;

    cout << a.surface() << endl;
    return 0;
}
   
위의 예제코드에서 a를 클래스 vector 의 인스턴스(INSTANCE)라고 한다.

 


1.16절. 생성자 / 소멸자

만들수 있는 메서드 중에는 생성자(Constructor)와 소멸자 (Destructor), 이것들은 인스턴스가 생성되고 소멸될때 자동적으로 호출되는 메서드이다.

생성자는 인스터스의 여러가지 변수를 초기화하거나, 메모리 할당등의 작업을 위해서 쓰인다. 다음은 오버로드된 2개의 생성자를 이용한 셈플코드이다.

#include <iostream>

using namespace std;

class vector
{
    public:
        double x;
        double y;
        vector()
        {
            x = 0;
            y = 0;
        }
        vector(double a, double b)
        {
            x = a;
            y = b;
        }

};

int main()
{
    vector k;
    cout << "vector k: " << k.x << "," << k.y << endl;

    vector m(45, 5);
    cout << "vector m: " << m.x << "," << m.y << endl;

    k = vector (22, 13);
    cout << "vector k: " << k.x << "," << k.y << endl;
}
   
하지만 이미 앞에서 배운 default parameter 을 사용하면, 번거롭게 overload 하지 않고 코드를 단순화 시킬수 있다.
#include <iostream>

using namespace std;

class vector
{
    public:
        double x;
        double y;
        vector(double a = 0, double b = 0)
        {
            x = a;
            y = b;
        }

};

int main()
{
    vector k;
    cout << "vector k: " << k.x << "," << k.y << endl;

    vector m(45, 5);
    cout << "vector m: " << m.x << "," << m.y << endl;

    vector p(5);
    cout << "vector p: " << p.x << "," << p.y << endl;
}
   

 

소멸자는 그리 필요하지 않는경우가 많다. 보통은 인스턴스가 제대로 종료되었는지 확인하고, 종료될때 어떤 값을 가지고 종료되는지 알고자하는 목적(DEBUG) 으로 많이 사용된다. 그러나 만약 인스턴스에서 메모리 할당을 했다면 (new 나 malloc 로) 인스턴스를 종료시키기 전에 반드시 메모리를 해제(free) 시켜줘야 한다. 이럴경우 소멸자는 매우 유용하게 사용된다.

#include <iostream>

using namespace std;

class person
{
    public:
        char *name;
        int age;

    person(char *n ="no name", int a = 0)
    {
        name = new char[40];
        strncpy(name, n, 40);
        age = a;
    }

    ~person()
    {
        cout << name << " : 40 byte is free : Instance going to be deleted" << e
ndl;
        delete []name;
    }
};

int main()
{
    person me("yundream", 25);
    cout << "name is " << me.name << endl;
    cout << "age is " << me.age << endl;

    person *my;
    my = new person("hello");
    cout << "name is " << my->name << endl;
    cout << "age is " << my->age << endl;
    delete my;
    return 0;
}
   
(할당된 메모리는 free 를 하거나 프로세스가 종료되지 않는한은 커널에 되돌려지지 않는다.)

 


1.17절. 클래스 메서드의 선언과 정의 분리

만약 메서드를 inline 으로 작성하고 싶지 않다면, 클래스에는 단지 선언만을 포함하게 유지하고, 메서드의 원형을 별도로 관리하도록 할수 있다.

#include <iostream>
using namespace std;

class vector
{
    public:
        double x;
        double y;

        double surface();
};

double vector::surface()
{
    double s= 0;
    for (double i = 0; i < x; i++)
    {
        s = s + y;
    }
    return s;
}

int main()
{
    vector k;

    k.x = 5;
    k.y = 6;
    cout << k.surface() << endl;

    return 0;
}
   
이렇게 분리할경우 inline 에 비해서 약간의 속도저하가 있을수 있겠지만, 유지/보수가 수월해질것이다.

 


1.18절. 객체의 배열

당연히 객체를 배열로 선언하는 것도 가능하다.

#include <iostream>
#include <cmath>
using namespace std;

class vector
{
    public:
        double x;
        double y;

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
        }

        double module()
        {
            return sqrt (x*x + y*y);
        }
};

int main()
{
    vector t[3] = {vector(4,5), vector(5,5), vector(2,5)};

    cout << t[0].module() << endl;
    cout << t[1].module() << endl;
    cout << t[2].module() << endl;

    return 0;
}
   

 


1.19절. 클래스 멤버변수의 static 선언

클래스 맴버변수는 static 로 선언될수 있으며, static 로 선언되었을경우 모든 인스턴스에서 공유해서 사용할수 있다. 단. static 으로 선언된 변수의 초기화는 클래스의 밖에서만 가능하다.

#include <iostream>
#include <cmath>
using namespace std;

class vector
{
    public:
        double x;
        double y;
        static int count;

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
            count ++;
        }

        ~vector()
        {
            count --;
        }
};

int vector::count = 0;

int main()
{
    cout << "Number of vector : " << endl;
    vector a;
    cout << vector::count << endl;
    vector b;
    cout << vector::count << endl;

    vector *r, *u;

    r = new vector;
    cout << vector::count << endl;
    u = new vector;
    cout << vector::count << endl;

    delete r;
    cout << vector::count << endl;
    delete u;
    cout << vector::count << endl;

    return 0;
}
   
위의 vector 클래스는 count 라는 static 변수를 가지고 있다. 이 변수는 현재 vector 클래스의 인스턴스의 갯수를 계수하기 위한 용도로 사용된다. vector 클래스의 새로운 인스턴스가 만들어지면 count 를 증가하고 인스턴스가 소멸되면 count 를 감소시킴으로써 인스턴스의 갯수를 유지한다.

 


1.20절. 클래스 멤버변수의 상수선언

클래스 멤버변수가 static 로 선언되는것과 마찬가지로 상수 (constant)로 선언될수도 있다. 이 변수는 클래스안에서 값이 할당되며, 인스턴스에서 변경될수 없다. 그러나 단지 const 로만 선언했을경우 컴파일러에 따라서 컴파일이 안될수도 있다. 예를들어 gnu 컴파일러의 경우 const static 로 선언해야 될경우가 있다.

#include <iostream>
#include <cmath>
using namespace std;

class vector
{
    public:
        double x;
        double y;
        const static double pi = 3.1415927;

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
        }

        double cilinder_volume()
        {
            return x*x/4*pi*y;
        }
};

int main()
{
    cout << "pi is: " << vector::pi << endl;
    vector k (3,4);
    cout << "Result: " << k.cilinder_volume() << endl;
    return 0;
}
   

 


1.21절. this 포인터

클래스에서 각 메서드는 주소에 의한 방식으로 함수를 호출한다. 이렇게 할수 있는 이유는 this 라는 가상의 포인터 때문이다. 클래스에 선언된 모든 메서드는 this 를 명시하지 않더라도 this 가 있는것으로 간주되고 주소에 의해서 함수가 호출된다. 이렇게 하는 이유는 클래스내의 멤버함수를 객체에 의해서 소유하도록 하기 위함이 목적이다. 즉 this 는 보이지 않는 포인터로 객체와 멤버함수를 내부적으로 연결하는 일을 한다.

#include <iostream>
#include <cmath>

using namespace std;


class vector
{
    protected:
        double k;
    public :
        double x;
        double y;
        vector(double a= 0, double b= 0)
        {
            x = a;
            y = b;
        }
        double module()
        {
            cout << "module " <<  x << " : " << y<< endl;
            return sqrt(x*x + y*y);
        }

        void set_length(double a = 1)
        {
            double length;
            length = this->module();

            x = x/length *a;
            y = y/length *a;
        }
};


int main()
{
    vector a(3,5);
    cout << "--> " << a.module() << endl;
    a.set_length(2);
    cout << "--> " << a.module() << endl;
    a.set_length();
    cout << "--> " << a.module() << endl;
}
   

 


1.22절. 상속

클래스는 다른 클래스로 부터 파생(Derived)될수 있다. 이 새로운 클래스는 원본클래스의 메서드와 변수를 상속 (Inherits) 받게 된다. 이렇게 해서 파생된 클래스는 새로운 메서드와 변수들을 추가함으로써 확장시켜 나갈수 있게 된다.

 
#include <iostream>
#include <cmath>
using namespace std;
    
// 원본 클래스
class vector
{
    public:
        double x;
        double y;
        const static double pi = 3.1415927; 

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
        }

        double surface()
        {
            return x * y;
        }
};

// vector 로부터 파생된 새로운 클래스
// 원본 vector 클래스의 표면적을 구하는 작업외에 
// 체적을 구하는 작업을 할수있도록 확장되었다. 
class trivector: public vector
{
    public :
        double z;

        // trivector 생성자가 호출되기 전에
        // vector 생성자가 호출되어서 m, n 인자를 
        // 초기화 한후, 거기에 3차원 지원을 위해서 p 가 
        // 초기화 된다.  
        trivector(double m =0, double n =0, double p=0): vector(m,n)
        {
            z = p;
        }

        // 또다른 생성자로 만약에 2차원 정보가 
        // 들어왔을경우 3차원으로 변경한다.  
        trivector(vector a, double p = 0)
        {
            x = a.x;
            y = a.y;
            z = p;
        }

        // 3차원 데이타를 이용해서 체적을 구한다. 
        // surface()메서드를 호출해서 표면적을 구하고 
        // 거기에 높이인 z 를 곱해주면 된다. 
        double volume()
        {
            return this->surface() * z;
        }
};

int main()
{
    vector a(4, 5);
    trivector b(1, 2, 3);
    trivector c(a);

    cout << "surface a: " << a.surface() << endl;
    cout << "volume  b: " << b.volume() << endl;
    cout << "surface b: " << b.surface() << endl;
    cout << "volume  c: " << c.volume() << endl;

    trivector d(a,5.8);
    cout << "volume  d: " << d.volume() << endl;
}
   

 


1.23절. 다중상속

바로 위에서 상속에 대해서 알아봤는데, C++ 은 1개 이상의 클래스로 부터 상속받는 것도 가능하다. 그러나 다중상속을 이용해서 클래스를 만들경우 나중에 유지/보수가 곤란해지는 문제가 생길수 있음으로, 대체적으로 다중상속은 지양하는 추세이다.

#include <iostream>
#include <cmath>
using namespace std;

// 원본 클래스
class vector
{
    public:
        double x;
        double y;
        const static double pi = 3.1415927;

        vector (double a=0, double b=0)
        {
            x = a;
            y = b;
        }

        double surface()
        {
            return x * y;
        }
};

class height
{
    public :
        double z;
        height (double a)
        {
            z = a;
        }

        int is_negative()
        {
            if (z < 0) return 1;
            else       return 0;
        }
};

class trivector: public vector, public height
{
    public :
        trivector(double a= 0, double b=0, double c=0): vector(a,b), height(c)
        {
        }
        double volume()
        {
            return fabs(x* y* z);
        }
};

int main()
{
    trivector a(2, 3, -5);

    cout << a.volume() << endl;
    cout << a.surface() << endl;
    cout << a.is_negative() << endl;
}
   

 


1.24절. 캡슐화(은닉)

아마 당신이 C++ 을 처음접해 보았다면, 위의 코드에서 public: 라고 하는 생소한 키워드를 보았을것이다. 이것은 C++ 에서 새로추가된 키워드로 메서드나 멤버변수에 엑세스레벨을 부여하게 된다.

public: 는 프로그램어디에서든지 엑세스 할수 있음을 나타낸다. 이것은 원본클래스와 파생클래스에게 모두 동일하게 적용된다.

private: 는 단지 원본 클래스의 메서드를 통해서만 접근이 가능하다.

protected: private 와 비슷하게 클래스 메서드를 통해서만 접근이 가능하지만, private 와는 달리 원본뿐 아니라 파생된 클레스에서의 접근도 가능하다.

 

#include <iostream>
#include <cmath>

using namespace std;


class vector
{
    private:
        double x;
        double y;
    public :
        double surface()
        {
            return x * y;
        }
};

int main()
{
    vector b;
    b.x = 2; // 컴파일 에러발생
    b.y = 3; // 컴파일 에러발생
}
   
위의 경우 c++ 컴파일러로 컴파일할경우 `double vector::x' is private 와 같은 에러메시지를 출력하고 컴파일 중지된다. vector 클래스의 멤버변수 x, y 는 private 로 선언되어 있음으로 단지 현재 클래스의 메서드를 통해서만 접근가능하기 때문이다. 이럴경우 x, y 입력을 위한 전용 메서드를 하나 만들어야 할것이다.
#include <iostream>
#include <cmath>

using namespace std;


class vector
{
    private:
        double x;
        double y;
    public :
        double surface()
        {
            return x * y;
        }
        void input(double a, double b)
        {
            x = a;
            y = b;
        }
};

int main()
{
    vector b;
    b.input(11, 40.5);
    cout << b.surface() << endl;
}
   

 


1.25절. 가상함수

원본클래스에서 파생된 새로운 클래스는 원본 클래스의 메서드와 멤버변수를 상속받는다는 것을 배워서 알고 있다. 그런데 이런경우를 생각할수 있을것이다. vector 에 module 란 메서드가 있는데, 이 메서드는 다음과 같다.

double module()
{
    return sqrt(x*x + y*y); 
}
   
만약 vector 에서 파생된 trivector 이란 클래스를 선언했다면, trivector 클래스는 vector->module() 를 상속받게 될것이다. 그러나 trivector 의 경우 sqrt 연산을 할때 3차원 데이타를 가지고 연산을 해야 할것이다.
double module()
{
 return sqrt(x*x + y*y + z*z);
}
   
이처럼 메서드를 상속받았을때, 상속받은 메서드의 연산방식이 변경될경우 virtual 로 선언하면 된다.
#include <iostream>
#include <cmath>

using namespace std;


class vector
{
    public :
        double x;
        double y;
        virtual double module()
        {
            return sqrt(x*x + y*y);
        }
};

class trivector: public vector
{
    public :
        double z;

    trivector(double m=0, double n=0, double p=0)
    {
        x = m;
        y = n;
        z = p;
    }

    double module()
    {
        return sqrt(x*x + y*y + z*z);
    }
};

int main()
{
    trivector b(2,3,4);
    cout << b.module() << endl;
}
   

 


1.26절. 파일스트림 처리

C++ 은 파일처리를 위한 매우 간단한 방법을 제공한다. 다음은 파일을 읽기 위한 코드이다.

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    fstream f;
    char c;

    f.open("seek3.c", ios::in);
    while (! f.eof())
    {
        f.get(c);
        cout << c;
    }

    f.close();

    return 0;
}
   
다음은 파일에 쓰기 위한 코드이다.
#include <iostream>
#include <fstream>
#include <cstdio>
using namespace std;

int main()
{
    fstream f;
    f.open("text.txt", ios::out);

    f << "Hello world " << endl;

    f.close();
    return 0;
}
   

 


1.27절. 정형화된 출력

보통 표준 C 언어에서는 printf 를 이용해서 정형화된 출력을 수행한다. C++ 에서는 width() 와 setw()를 이용해서 정형화된 출력을 한다. 이것들은 단지 가장최근의 출력에만 영향을 미친다.

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    for (int i = 1; i <= 1000; i *=2)
    {
        cout.width(7);
        cout << i << endl;
    }
    for (int i = 0; i <=10 ;i ++)
    {
        cout << setw(3) << i << setw(5) << i * i * i << endl;
    }
    return 0;
}
   

 


1.28절. 문자배열을 file 처럼이용하기

좀 이상하게(혹은 쓸모없는 것처럼) 들릴수 있겠지만, 문자배열을 파일처럼 연산하는게 가능하다. 이것은 파일 스트림과 메모리를 연결해서 사용하는 프로그래밍 기법을 가능하도록 해준다.

#include <iostream>
#include <cmath>
#include <cstring>
#include <strstream>

using namespace std;

int main()
{
    char a[1024];
    ostrstream b(a, 1024);

    b.seekp(0); // 스트림의 첫번째로 이동 
    b << "2+2 = " << 2+2 << ends; // ends 임에 주의
    cout << a << endl;

    double v = 49;
    strcpy(a, "A sinus: ");

    b.seekp(strlen(a));
    b << "sin (" << v << ") = " << sin(v) << ends;
    cout << a << endl;
}
   
#include <iostream>
#include <cmath>
#include <cstring>
#include <strstream>

using namespace std;

int main()
{
    char a[1024];
    istrstream b(a, 1024);

    strcpy(a, "45.656");
    double k, p;

    b.seekg(0);
    b >> k;

    k = k+1;
    cout << k << endl;

    strcpy(a, "444.23 56.89");
    b.seekg(0);
    b >> k >> p;

    cout << k << ", " << p + 1 << endl;
    return 0;
}
   

 

Tag :    
category_C++


반응형

'차근차근 > C' 카테고리의 다른 글

MSB3073 에러  (0) 2014.08.01
비쥬얼 스튜디오 디버깅 팁 ( Visual Studio Debugging Tips )  (0) 2014.07.30
c++ 기본 문법 정리  (0) 2014.07.29
Edit Plus+MinGW+gcc 컴파일 설정  (0) 2014.07.29
c++ ] 네임스페이스 (namespace)  (0) 2014.07.29