[OODP] 8. Working with Classes

POSTECH OODP Lecture at 24SS

Overloading the « Operator

본래 «는 bit shift operator지만, ostream class는 « 연산자를 overload 했다.

cout << 1 << 2.0 << "three" << endl;

cout << a << b;
(cout.operator<<(a)).operator<<(b);
operator<< (operator<<(cout, a), b);

개발자가 직접 « 연산자를 overloading 할 수도 있다. 일단 overload하면, cout을 비롯한 다른 ostream 객체에서도 사용할 수 있다.

class Complex
{
private:
    double real, imag;
public:
    friend ostream &operator<<(ostream &os, const Complex&x) {
        os << x.real << "+" << x.imag << "i";
        return os;
    }
}

Complex  c = a * 3.0 + b * b;
cout << c << endl;

ofstream f_out("test.txt");
f_out << "File output: " << c << endl;

Overloading the Unary - Operator

Automatic Comversions and Type Casts for Classes

C++이 built-in types들 간의 conversion을 어떻게 다루는지 확인해보자.

// Automatic type conversion
long count = 8;     // int value 8 converted to type long
double time = 11;   // int value 11 converted to type double
int side = 3.33;    // double value 3.33 converted to type int 3

// Type cast
int *p = 10;            // invalid. 10 is not an address. no automatic type conversion
int *p = (int *) 10;    // int 10 is converted to an address using a type cast

C++이 user-defined types의 conversion을 어떻게 다루는지 확인해보자.

class Complex
{
private:
    double real, imag;
public:
    Complex() {}
    Complex(double r, double i = 0.0) { real = r; imag = i; }
    // ...
};

int main()
{
    Complex c;
    c = 100.;   // c = Complex(100.); => c = Complex(100., 0.);
    cout << c << endl;
    return 0;
}

Complex의 생성자가 하나의 argument를 가진 것으로 인식해 automatic type conversion이 발생했다. 무척 편리하지만, 예상치 못한 부작용이 발생할 수 있다. automatic conversion을 막기 위해서는 ‘explicit’을 사용해야한다.

class Complex
{
    // ...
    explicit Complex(double r, double i = 0.0) { real = r; image = i; }
    // ...
};

Complex x;      // create a Complex number object
x = 15.2;       // not valid if Complex(double r) is declared as explicit
x = Complex(15.2);      // ok, an explicit conversion
x = Complex(15.2, 3.0); // x = 15.2 + 3.0i
x = (Complex)15.2;      // ok, old form for explicit typecast

이제 우리는 int(x)와 같은 표현이 class object의 생성자를 호출하여 typecast를 고정한다는 것을 알 수 있다.

지금까지 native type의 값을 생성자를 사용하여 user-defined type으로 convert하는 방법을 살펴보았다. 그 반대도 알아보자.

Complex x(10.0, 2.0);
double y = x;

위 코드는 당연히 오류가 발생한다. double은 native type이기 때문에 class constructor가 존재하지 않기 때문이다. 대신, 이 코드를 동작하게 하려면 operator overloading이 필요하다. 이를 conversion function이라고 부른다.

class Complex
{
    // ...
public:
    operator double() const { return real; }
    // ...
};

Complex c(100., 3.);
double x = c;
// equivalent to 
// x = c.operator double();
// x = (double)c;
// x = double(c);

만약 type conversion은 허용하지만, automatic type conversion은 방지하고 싶다면 위와 마찬가지로 explicit을 사용하면 된다.

explicit operator double() const { return real; }

Complex x(100.0, 3.0);
double y = x;       // invalid
double y = double(x);   // yes
double y = (double)x;   // yes
double y = x.operator double(); // ?

Questions?

Q1. nonmember function이 뭔가요?
A1.

Q2.
A2.