[C++] C++ overview

2023. 10. 11. 00:10Run/C++

 

1.  Intro & Variable

Object-Oriented Programming (OOP)

  • Programming paradigm that represents the concepts of objects that have data fields and associated procedures
  • Data field: attributes that describe the objects
  • Objects
    • usually instances of classes
    • used to interact with one another to design application and computer programs
  • OOP languages: C++, Objective-C, Smalltalk, Delphi, Java, Javascript, C#, Perl, Python, Ruby, PHP, ...
  • 3 Characteristics of OOP
    • Encapsulation (캡슐화)
      • Packing of data and functions into a single component
      • Selective hiding of data and functions
    • Polymorphism (다형성)
      • Single interface to entities of different types
      • Can be applied to both function and operator
      • Ex) '+' operator는 integer, floating point, string 등 여러 data type에서 쓰임
    • Inheritance (상속성)
      • Can define a class interms of another class
      • Can reuse the code functionality and fast implementation time
      • Relationships of classes through inheritance → create hierarchy(계층구조)

Standard Output (cout)

  • Used together with the insertion operator (<<)
  • Multiple insertion operations can be chained
  • Line break → new-line character (\n) or endl manipulator

Standard Input (cin)

  • Used together with the extraction operator (>>)
  • Uses the type of the variable after >> operator to determine how it interprets the characters read from the input
  • Multiple extraction operations can be chained

Variable

  • Life-Cycle (Scope) of Variables
    • Time between a variable's creation & destruction
    • Available scope of a variable
    • Varaible defined in a block can be accessed only inside the block
int var = 1;
{
    char var = 'a';
    {
        cout << "Var 1 = " << var << endl;
    }
    cout << "Var 2 = " << var << endl;
}
cout << "Var 3 = " << var << endl;

// Var 1 = a
// Var 2 = a
// Var 3 = 1
  • Variable Classification
    • 선언 위치에 따른 구분: Local, Global
    • 저장 위치에 따른 구분: Auto, Static, Register
    • Local variable
      • Declared within subroutines or programming blocks
      • 그 안에서만 사용 가능
    • Global variable
      • Declared at the start of the program
      • 어디에서나 사용 가능

Structure

  • Data Type
    • Classification of data
    • Store a specific type of information
  • Primitive Data Type (원시 자료형)
    • Provided by a programming language (ex. char, int, float, double, ...)
  • Object Reference Type
    • Defined by a programmer (ex. structure, class)
  • Structure
    • Complex data type declaration that defines a physically grouped list of variables to be placed under one name in a block of memory
    • Can be accessed via a single pointer or the declared name
// 방법 1
struct name {
    type member1;
    type member2;
    ...
};
struct name object1, object2;

// 방법 2
typedef struct name {
    type member1;
    type member2;
    ...
}sname;
sname object1, object2;
#include <iostream>

struct Student {
    int id;
    float grade;
};

int main() {
    struct Student st;
    cout << "학번: ";
    cin >> st.id;
    cout << "성적: ";
    cin >> st.grade;
    cout << "학번 " << st.id << " 성적 " << st.grade << endl;
    return 0;
}

요약

  Primitive Array Structure
Declaration int a; int a[3]; struct student st;
Access a = 10; a[0] = 1;
a[1] = 2;
a[2] = 3;
st.id = 20191010;
st.grade = 4.5;
st.gender = 1;
Initialization int a = 10; int a[3] = {1, 2, 3}; struct student st = {20191010, 4.5, 1};

Namespace

  • Container for a set of identifiers such as variables & functions
  • Provide a level of direction to specific identifiers
  • Make it possible to distinguish between identifiers with the same name
  • Can be accessed by using '::' operator
namespace AA {
    char val = 'A';
    void func(char i) {
        cout << "AA Input: " << i << endl;
    }
}

namespace BB {
    char val = 'B';
    void func(char i) {
        cout << "BB Input: " << i << endl;
    }
}

int main() {
    AA::func(AA::val);
    BB::func(BB::val);
    return 0;
}

Data Type Conversion

  • Implicit type conversion
    • Automatic type conversion by the compiler
    • Mixed-type expression → types can be converted to a supertype as needed at runtime
  • Explicit type conversion
    • Explicitly defined within a program
float concentration = 0;
float real_concentration = 0;

// without type conversion
concentration = (30 / 40) * 100; // 0 * 100
cout << "Weight percent = " << concentration << endl;

// with type conversion
real_concentration = (float)30 / 40 * 100; // 0.75 * 100
cout << "Real Weight percent = " << real_concentration << endl;

 

5. Function

Function

  • Named block of code that performs a task and then returns control to a caller
  • Often executed several times, from several different places
  • After finishing a subroutine, program will branch back to the point after the call
return_type function_name(parameter list) {
    /* body of the function */
}

Function Call

  • Input and Output of Function
int add(int a, int b) {
    int result = a + b;
    return result;
}

int main() {
    int z;
    z = add(1, 2);
    return 0;
}

Inline Function

  • 한 번 정의되면, function 불릴 때마다 compiler가 function call을  actual code from the function으로 대체
  • 기본 function보다 조금 더 빨리 동작함(function-calling-overheads 저장되기 때문), but has a memory penalty
    • ex) inline function 10번 호출되면 10개의 function 복사본이 code에 삽입됨
  • Best for small function that are called often
  • 컴파일 시점에 컴파일러가 호출 부분에 함수의 코드를 직접 삽입하는 방식으로 작동 → 함수 호출 관련 오버헤드 ↓
inline int max(int num1, int num2) {
    /* body of the function */
}

max(a, b);

Recursive Functions 재귀 함수

  • Function which either calls itself or is in a potential cycle of functions calls
  • ex) summation, factorial, fibonacci, ...
int Sum(int n) {
    if (n==1) return 1;
    else return n + Sum(n-1);
}

int Factorial(int n) {
    if (n==1 or n==2) return n;
    else return n * Factorial(n-1);
}

int Fibo(int n) {
    if (n==1 or n==2) return 1;
    else return Fibo(n-2) + Fibo(n-1);
}

int main() {
    int result1 = Sum(4);
    int result2 = Factorial(4);
    int result3 = Fibo(4);

    cout << "Sum: " << result1 << endl;
    cout << "Factorial: " << result2 << endl;
    cout << "Fibo: " << result3 << endl;
    
    return 0;
}

 

6. Class

Class

  • User defined type or data structure
  • Instance (= object)
    • Speicifc realization of a class
    • 각 instance는 고유의 data 가짐
    • Creation of realized instance = Instantiation (인스턴스 생성)
    • Class가 붕어빵 틀이라면, Instance는 붕어빵 틀로 만든 붕어빵
class Fish {
    public:
    void Swim() {
        printf("You invoke swim()\n");
    }
};

int main() {
    Fish fish;
    fish.Swim();
    return 0;
}
  • Access specifiers
    • Define the access rights for the statements or functions
    • private: accessible only within the same class
    • public: accessible within the class & outside the class
    • protected: cannot be accessed from outside the class, but can be accessed from a derived class
class Quadrangle {
    private:
        int width;
        int height;
        int area;

    public:
        int CalculateArea(int argWidth, int argHeight) {
            width = argWidth;
            height = argHeight;
            area = width * height;
            return area;
        }
};

int main() {
    Quadrangle q;
    cout << q.CalculateArea(10, 3) << endl;
    return 0;
}
class Quadrangle {
    private:
        int width;
        int height;
        int area;

    public:
        int CalculateArea(int argWidth, int argHeight); // Declaration
};

// Definition
int Quadrangle::CalculateArea(int argWidth, int argHeight) {
    width = argWidth;
    height = argHeight;
    area = width * height; 
    return area;
}

int main() {
    Quadrangle q;
    cout << q.CalculateArea(10, 3) << endl;
    return 0;
}
class Quadrangle {
    private:
        int width;
        int height;
        int area;

    public:
        int CalculateArea();
        void SetWidth(int w);
        void SetHeight(int h);
};

int Quadrangle::CalculateArea() {
    area = width * height; 
    return area;
}

void Quadrangle::SetWidth(int w) {
    width = w;
}

void Quadrangle::SetHeight(int h) {
    height = h;
}

int main() {
    int w, h;
    Quadrangle cQ;

    cout << "Width: ";
    cin >> w;
    cout << "Height: ";
    cin >> h;

    cQ.SetWidth(w);
    cQ.SetHeight(h);

    printf("Area (w=%d, h=%d) = %d \n", w, h, cQ.CalculateArea());
   	
    return 0;
}

Constructor and Destructor

  • Constructor 생성자
    • Class의 instance 생성될 때마다 constructor 불림
    • Class와 같은 이름, 아무것도 return 하지 않음
    • Constructor 만들지 않아도 compiler가 알아서 implicit default constructor 생성
  • Destructor 소멸자
    • Class의 instance 제거될 때마다 destructor 불림
    • Class와 같은 이름, 앞에 '~' 붙임
    • Destructor 만들지 않아도 compiler가 알아서 implic default destructor 생성
class Unit {
    int status;
    public:
        Unit(); // Constructor
        ~Unit(); // Deconstructor
        void fly();
}

Unit::Unit() {
    cout << "Constructor" << endl;
    status = 1;
}

Unit::~Unit() {
    cout << "Destructor" << endl;
    status = 0;
}

void Unit::fly() {
    cout << status << endl;
}

int main() {
    Unit oUnit;
    oUnit.fly();
    return 0;
}

/*
Result:
Constructor 
1
Destructor
*/
// Argument 사용하는 Constructor

class Unit {
    int status;
    public:
        Unit(int a);
        ~Unit();
        void fly();
};

Unit::Unit(int a) {
    cout << "Constructor " << a << endl;
    status = a;
}

Unit::~Unit() {
    cout << "Destructor" << endl;
    status = 0;
}

void Unit::fly() {
    cout << status << "\n";
}

int main() {
    Unit oUnit(1);
    oUnit.fly();
    return 0;
}

1) Constructor/Destructor 사용 안하는 방법

class Student {
    private:
        int year;
        int id;
        int grade;
    public:
        void SetData(int y, int i, int g);
        void showData();
};

void Student::SetData(int y, int i, int g) {
    year = y;
    id = i;
    grade = g;
}

void Student::showData() {
    cout << "Year: " << year << ", ID: " << id << ", Grade: " << grade << endl;
}

int main() {
    Student s;
    s.SetData(2017, 100100, 1);
    s.showData();
    return 0;
}

2) Constructor/Destructor 사용 하는 방법

class Student {
    private:
        int year;
        int id;
        int grade;
    public:
        Student(int y, int i, int g);
        ~Student();
        void showData();
};

Student::Student(int y, int i, int g) {
    year = y;
    id = i;
    grade = g;
}

void Student::showData() {
    cout << "Year: " << year << ", ID: " << id << ", Grade: " << grade << endl;
}

int main() {
    Student s(2017, 100100, 1);
    s.showData();
    return 0;
}

Inheritance

  • Define a class in terms of another class
  • Mechanism for code reuse
  • Allow independent extensions of the original software
// Parent class
class NPC {
    int defense;
    public:
        void SetDefense(int n);
        int GetDefense();
};

// Child class
class Grunt : public NPC {
    int armor;
    public:
        void SetArmor(int n);
        int GetArmoredDefense();
};

void NPC::SetDefense(int n) {
    defense = n;
}

int NPC::GetDefense() {
    return defense;
}

void Grunt::SetArmor(int n) {
    armor = n;
}

int Grunt::GetArmoredDefense() {
    return armor+GetDefense();
}

int main() {
    Grunt oUnit;
    oUnit.SetDefense(10);
    oUnit.SetArmor(20);
    cout << "Get Armored Defense: " << oUnit.GetArmoredDefense() << endl;
    return 0;
}

Public, Private, Protected, and Inheritance

class P {
    public:
    	int x;
    protected:
        int y;
    private:
        int z;
};

class A : public P {
    // x = public
    // y = protected
    // z = not accessible
};

class B : protected P {
    // x = protected
    // y = protected
    // z = not accessible
};

class C : private P {
    // x = private
    // y = private
    // z = not accessible
};

Multiple Inheritance

  • 하나 이상의 parent class로부터 상속받을 수 있음
// Parent classes
class NPC {
    /* body of NPC */
};
class Display {
    /* body of Display */
};

// Child class
class Grunt : public NPC, public Display {
    /* body of Grunt */
}

Pointer to Class

  • Pointer to structure와 동일한 방식으로 동작
  • Class member에 접근하기 위해 member access operator '->'가 사용됨
Grunt *pUnit = new Grunt;
pUnit->SetDefense(10);
pUnit->SetArmor(20);
delete pUnit;

Grunt oUnit;
Grunt *pUnit;
pUnit = &oUnit;
pu=Unit->SetDefense(10);
pUnit->SetArmor(20);

Inheritance and Constructor

  • Constructor는 상속되지 않음
  • Parent constructor는 child constructor에 의해 암시적 또는 명시적으로 호출됨
  • Parent class의 constructor가 먼저 호출되고, child class의 constructor가 나중에 호출됨
class Base {
    public:
        Base();
        ~Base();
};

Base::Base() {
   cout << "Constructor of Base" << endl; 
}

Base::~Base() {
    cout << "Destructor of Base" << endl;
}

class Derived : public Base {
    public:
        Derived();
        ~Derived();
};

Derived::Derived() {
    cout << "Constructor of Derived" << endl;
}

Derived::~Derived() {
    cout << "Destructor of Derived" << endl;
}

int main() {
    Derived obj;
}

/*
Result
Constructor of Base
Constructor of Derived
Destructor of Derived
Destructor of Base
*/

Constructor Call

  • Implicit Constructor Call
class Base {
    public:
        Base(int a);
        ~Base();
};

Base::Base() {
   cout << "Constructor of Base" << endl; 
}

Base::~Base() {
    cout << "Destructor of Base" << endl;
}

class Derived : public Base {
    public:
        Derived(int a);
        ~Derived();
};

Derived::Derived(int a) {
    cout << "Constructor of Derived " << a << endl;
}

Derived::~Derived() {
    cout << "Destructor of Derived" << endl;
}

int main() {
    Derived obj(1);
    return 0;
}

/*
Result
Constructor of Base
Constructor of Derived 1
Destructor of Derived
Destructor of Base
*/

// 이 외에는 에러
  • Explicit Constructor Call
class Base {
    public:
        Base(int a);
        ~Base();
};

Base::Base(int a) {
   cout << "Constructor of Base " << a << endl; 
}

Base::~Base() {
    cout << "Destructor of Base" << endl;
}

class Derived : public Base {
    public:
        Derived(int a);
        ~Derived();
};

Derived::Derived(int a) : Base(a) {
    cout << "Constructor of Derived " << a << endl;
}

Derived::~Derived() {
    cout << "Destructor of Derived" << endl;
}


int main() {
    Derived obj(1);
    return 0;
}

/*
Result
Constructor of Base 1
Constructor of Derived 1
Destructor of Derived
Destructor of Base
*/

 

7. Application of Class

Class Copy

  • 다른 변수들과 마찬가지로 class도 다른 class에 의해 copy 될 수 있음
  • Assignment operator '=' 사용

Data Copy

  • Shallow Copy 얕은 복사
    • B가 A 복사하면 A의 모든 field value 복사하게 됨
    • 가령 field value가 memory address라면, memory address를 복사
    • B의 field의 memory address 수정하면 A의 그것도 수정하는 것
  • Deep Copy 깊은 복사
    • B가 A 복사하면 모든 field를 복사하며 동적으로 할당된 메모리의 복사본을 만듦
    • B를 수정해도 A에 영향 없음
    • 더 느리고 비싼 복사

Copy Constructor

  • 기존의 object의 복사본으로 새 object 생성하기 위해 필요한 constructor
  • Compiler는 각 class에 대해 자동으로 copy constructor 생성함
  • 필요에 따라 user-defined copy constructor 직접 생성해야 함
classname (classname &obj) {
    // body of constructor
}
Rec::Rec(Rec &obj) {
    cout << "Copy Constructor" << endl;
}

Data Copy Functions

  • copyFrom function: argument로부터 data 복사
  • copyTo function: argument로 data 복사, argument를 reference로 받아야 함

Class & Function

  • Class를 function의 argument(인자)로 넘기기
    • Object가 function의 parameter(매개변수)로 복사됨
    • Function의 parameter 수정하면 function 내에서만 수정되고 기존 class에는 변화 없음
  • Object를 반환하는 function
    • Object는 value로 반환됨
    • Class object를 pointer로 반환하는 게 value로 반환하는 것보다 효율적임

Friend Function

  • 일반적으로 class 밖에 정의된 함수는 class의 private/protected data에 접근할 수 없음
  • Class의 friend로 정의된 friend 함수는 접근 가능함
  • Friend는 member function은 아님
  • 함수는 여러 class의 friend가 될 수 있음

 

8. Array, Pointer, Reference

Array

  • Series of elements of the same type placed in contiguous memory locations
  • Can be individually referenced by adding an index to an identifier
type name[elements];
  • Class array는 쉽게 정의할 수 있음
  • But, class의 constructor에 주의해야 함
type name[elements] = {constructor1, ...};
Unit temp[2] = {Unit(1), Unit(2)}; // example
  • Class array 예제
#include <iostream>
#include <string>

using namespace std;

class Unit {
    private:
        int x;
        int y;
    public:
        Unit(int a) {
            x = a;
            y = a;
        }
        void Print() {
            cout << x << ", " << y << endl;
        }
};

int main() {
    Unit aUnit[2] = {Unit(1), Unit(2)}; // Array of Classes
    for (int i = 0; i < 2; i++) {
        cout << "aUnit[" << i << "] = ";
        aUnit[i].Print();
    }
    return 0;
}

Pointer

  • Pointer는 어떠한 변수의 주소를 직접 참조(= points to)하는 변수
  • Primitive data type에는 '*' operator 사용
  • Object pointer는 '->'와 '*' operator를 통해 object에 접근할 수 있음
  • this Pointer
    • C++의 모든 object는 this pointer를 통해 주소에 접근할 수 있음
    • 모든 member function의 implicit parameter임
  • Pointer 예제
#include <iostream>
#include <string>

using namespace std;

int main() {
    int number = 45;
    int* pNumber = NULL; // 포인터 변수 선언

    pNumber = &number; // 변수 주소 저장

    cout << "Address of Number: " << pNumber << endl; // 변수 주소 출력
    cout << "Value of Number: " << *pNumber << endl; // 변수 주소가 가리키는 값 출력

    return 0;
}
  • Object Pointer 예제
#include <iostream>
#include <string>

using namespace std;

class Unit {
    private:
        int x;
        int y;
    public:
        Unit(int a, int b) {
            x = a;
            y = b;
        }
        void Print() {
            cout << x << ", " << y << endl;
        }
};

int main() {
    Unit aUnit[2] = {Unit(1, 2), Unit(3, 4)};

    Unit* pUnit = aUnit; // aUnit[0] 주소값 저장

    cout << "Using '->' operator" << endl;
    for (int i = 0; i < 2; i++) {
        pUnit->Print();
        pUnit++; // aUnit[1]로 이동
    }

    pUnit = aUnit;

    cout << "Using '.' operator" << endl;
    for (int i = 0; i < 2; i++) {
        (*pUnit).Print();
        pUnit++; // aUnit[1]로 이동
    }

    return 0;
}

New and Delete

  • Dynamic Memory Allocation (↔ Static Memory Allocation)
    • Run time 동안 memory가 즉시 할당됨
    • Compiler는 정확한 공간이나 item 개수를 미리 알 필요 없음
  • New and Delete operators
int *pInteger = new int;
int *pInterA = new int[10];
Unit *pUnit = new Unit(1, 2);
Unit *pUnitA = new Unit[2];
Unit *pUnitB = new Unit[2]{Unit(1, 2), Unit(3, 4)};

delete pInteger;
delete[] pIntegerA;
delete pUnit;
delete[] pUnitA;
delete[] pUnitB;
  • Dynamic Memory Allocation 예제
#include <iostream>
#include <string>

using namespace std;

int main() {
    int *pInteger = NULL;
    pInteger = new int;

    if (!pInteger) {
        cout << "Allocation Failed" << endl;
        return -1;
    }

    *pInteger = 777;
    cout << "pInteger = " << *pInteger << endl;
    
    delete pInteger;
    
    return 0;
}

Reference

  • 변수의 두 번째 이름을 만들 수 있음
  • 해당 변수에 저장된 original data를 읽거나 수정할 수 있음
  • 한 번 reference가 생성되면 다른 object를 reference 할 수 없음
int A = 5;
int &rA = A;
  • Pointer를 이용한 Swap vs Reference를 이용한 Swap
#include <iostream>
#include <string>

using namespace std;

void swap(int *x, int *y) {
    int t;
    t = *x;
    *x = *y;
    *y = t;
}

int main() {
    int i = 4;
    int j = 7;

    cout << "i: " << i << " j: " << j << endl;
    swap(&i, &j); // 변수의 주소값 넘겨줌
    cout << "i: " << i << " j: " << j << endl;

    return 0;
}
#include <iostream>
#include <string>

using namespace std;

void swap(int &x, int &y) {
    int t;
    t = x;
    x = y;
    y = t;
}

int main() {
    int i = 4;
    int j = 7;

    cout << "i: " << i << " j: " << j << endl;
    swap(i, j);
    cout << "i: " << i << " j: " << j << endl;

    return 0;
}

 

9. Function Overloading

Function Overloading

  • 이름이 같은 여러 개의 function을 만들 수 있음. 단, input argument는 달라야 함
void Add(int a);
void Add(int a, int b);
void Add(char a);
  • 예제
#include <iostream>
#include <string>

using namespace std;

int Add(int argNum1, int argNum2) {
    cout << "Add(int argNum1, int argNum2) is called" << endl;
    return argNum1 + argNum2;
}

double Add(double argNum1, double argNum2) {
    cout << "Add(double argNum1, double argNum2) is called" << endl;
    return argNum1 + argNum2;
}

double Add(int argNum1, double argNum2) {
    cout << "Add(int argNum1, double argNum2) is called" << endl;
    return argNum1 + argNum2;
}

int main() {
    Add(1, 1);
    Add(1.0, 1.0);
    Add(1, 1.0);
    return 0;
}

Constructor Overloading

  • Constructor Overloading
    • Function overloading과 비슷한 방식으로 overload 할 수 있음
    • 여러 constructor가 필요한 경우 constructor overloading 사용
    • Destructor는 overload 할 수 없음
  • Objective
    • 여러 initialization method를 사용해 class의 flexibility를 증가시키기 위함
    • Object array를 지원하기 위함
  • Constructor Overloaing 예제
#include <iostream>
#include <string>

using namespace std;

class Unit {
    private:
        int x;
        int y;
    public:
        Unit() {
            x = 0;
            y = 0;
        }
        // Constructor Overloading
        Unit(int a, int b) {
            x = a;
            y = b;
        }
        int GetX() {
            return x;
        }
        int GetY() {
            return y;
        }
};

int main() {
    Unit A; // call Unit()
    Unit B(10, 20); // call Unit(int, int)

    cout << "A: " << A.GetX() << ", " << A.GetY() << endl;
    cout << "B: " << B.GetX() << ", " << B.GetY() << endl;

    return 0;
}

Constructor & Memory Allocation

  • Copy Constructor
    • Object가 다른 object를 사용하여 initialize 될 때 불림
    • Object의 substitution(치환)에는 사용되지 않음
Unit A;
Unit B = A; // call copy constructor
Unit A, B;
B = A; // shallow copy, not copy constructor
  • Memory Allocation
    • Memory는 주로 constructor 안에서 할당됨 (copy constructor 포함)
    • 할당된 memory는 주로 destructor 안에서 제거됨

Default Argument

  • 직접 명시해줄 필요가 없는 function argument
  • Function 호출 중에 argument가 명시되지 않더라도, 항상 값이 있는 default argument를 명시할 수 있음
#include <iostream>
#include <string>

using namespace std;

void set(int x = 0, int y = 0) {
    cout << "x: " << x << ", y: " << y << endl;
}

int main() {
    set();
    set(1);
    set(1, 4);
    return 0;
}

Function Overriding

  • 이름이 같은 function은 base class, derived class에 모두 정의될 수 있음
  • Class 밖에서 function이 호출되면, derived class의 member function이 사용됨
  • Dervied class로부터 base class의 overriden function에 접근하려면, scope resolution operator :: 사용해야 함
#include <iostream>
#include <string>

using namespace std;

class Base {
    public:
        void getData() {}
};

class Dervied: public Base {
    public:
        void getData() {}
};

int main() {
    Dervied obj;
    obj.getData(); // Dervied의 getData() 실행됨
    return 0;
}
#include <iostream>
#include <string>

using namespace std;

class Base {
    public:
        void getData() {}
};

class Dervied: public Base {
    public:
        void getData() {
            Base::getData(); // Base의 getData() 실행됨
        }
};

int main() {
    Dervied obj;
    obj.getData(); // Dervied의 getData() 실행됨
    return 0;
}

 

10. Operator Overloading

Operator Overloading

  • 대부분의 built-in operator를 재정의하거나 overload 할 수 있음
  • User-defined type로 operator 사용할 수도 있음
  • Overload된 opeartor는 특정 이름을 가진 function이며, 키워드 'overload'와 operator symbol을 사용함
  • 다른 function과 마찬가지로 return type과 parameter list를 가짐
// Member function
// Plus operator
Unit Unit::operator+(Unit right) {}
  • Restrictions
    • Operator의 우선순위는 overloading의 영향을 받지 않음
    • Overload된 operator는 default argument를 가질 수 없음
    • Operator ::(scope resolution, 범위 지정), .(member access), .*(member access through pointer to member), ?:(ternary conditional)은 overload 될 수 없음
    • 새로운 operator 새로 만들 수 없음
    • =, [], (), -> 는 member function로만 정의될 수 있음
  • Overloading of Binary Operators(이항 연산자)
    • 첫 번째 object = operator overloaded function caller
    • 두 번째 object = passed argument
    • Function caller는 this pointer을 통해 접근할 수 있음
  • Binary Operator Overloading 예제
#include <iostream>
#include <string>

using namespace std;

class Unit {
    private:
        int hp;
    public:
        Unit() {hp = 0;}
        Unit(int i) {hp = 1;}
        int GetHP() {
            return hp;
        }
        Unit operator+(Unit right);
};

Unit Unit::operator+(Unit right) {
    Unit temp;
    temp.hp = hp + right.hp;
    return temp;
}

int main() {
    Unit Unit1(10), Unit2(5), Unit3;
    
    Unit3 = Unit1 + Unit2;

    cout << "Unit1 hp: " << Unit1.GetHP() << endl;
    cout << "Unit2 hp: " << Unit2.GetHP() << endl;
    cout << "Unit3 hp: " << Unit3.GetHP() << endl;

    return 0;
}

Overloadable/Non-overloadable Operators

  • Overload 가능한 operator:
+ - * / % ^
& | ~ ! , =
< > <= >= ++ --
<< >> == != && ||
+= -= /= %= ^= &=
|= *= <<= >>= [] ()
-> ->* new new [] delete delete []
  • Overload 불가능한 operator:
:: .* . ?:

Overloading of Comparison and Logical Operators

  • Comparison operator(비교 연산자), Logical operator(논리 연산자)는 overload 될 수 있음
  • 모든 built-in operator는 bool을 반환하며, 대부분의 user-defined operator 또한 bool을 반환함 (그래야 built-in과 호환)
  • 그러나, user-defined operator overload에서는 return type으로 아무 type이나 쓸 수 있음 (void 포함)
  • 비교 연산자 overloading 예제
#include <iostream>
#include <string>

using namespace std;

class Unit {
    private:
        int hp;
    public:
        Unit() { hp = 0; }
        Unit(int i) { hp = i; }
        int GetHP() { return hp; }
        int operator==(Unit right);
};

int Unit::operator==(Unit right) {
    if (hp == right.GetHP()) return 1;
    else return 0;
}

int main() {
    Unit Unit1(10), Unit2(5), Unit3(5);

    if (Unit1 == Unit2)
        cout << "Unit1 == Unit2" << endl;
    else
        cout << "Unit1 != Unit2" << endl;
    
    if (Unit2 == Unit3)
        cout << "Unit2 == Unit3" << endl;
    else
        cout << "Unit2 != Unit3" << endl;
}

Overloading of Unary Operators

  • Unary operator(단항 연산자)는 하나의 operand(피연산자)로 동작함
  • Input argument 가지지 않음 (postfix 제외)
  • Return type에 제약 없음 (ex. NOT operator가 int 값 리턴해도 됨)
  • Overload 가능한 unary operator: !, &, ~, *, +, -, ++, --, conversion operators
// Prefix
Unit Unit::operator++() {}

// Postfix
Unit Unit::operator++(int) {}
  • Unary operator overloading 예제
#include <iostream>
#include <string>

using namespace std;

class Unit {
    private:
        int hp;
    public:
        Unit() { hp = 0; }
        Unit(int i ) { hp = i; }
        int GetHP() { return hp; }
        Unit& operator++();
};

Unit& Unit::operator++() {
    hp++;
    return (*this);
}

int main() {
    Unit Unit1(1);

    cout << "Unit1 hp: " << Unit1.GetHP() << endl;
    ++Unit1;
    cout << "++Unit1 hp: " << Unit1.GetHP() << endl;
    
    return 0;
}

Overload Using Friend Function

  • Operator는 friend function으로 정의될 수 있음
  • Unary operator → 1 argument / Binary operator → 2 arguments
  • Assignment operator '='는 friend function이 아닌 member function을 통해 overload 될 수 있음
// Binary operator
Unit operator+(Unit left, Unit right) {}

// Unary operator - Prefix
Unit operator++(Unit left) {}

// Unary operator - Postfix
Unit operator++(Unit left, int) {}
  • Friend function 이용한 overloading 예제
#include <iostream>
#include <string>

using namespace std;

class Unit {
    private:
        int hp;
    public:
        Unit() { hp = 0; }
        Unit(int i) { hp = i; }
        int GetHP() { return hp; }
        friend Unit operator+(Unit left, Unit right); // friend function
};

Unit operator+(Unit left, Unit right) {
    Unit temp;
    temp.hp = left.hp + right.hp;

    cout << "left hp: " << left.hp << endl;
    cout << "right hp: " << right.hp << endl;
    cout << "result hp: " << temp.hp << endl;

    return temp;
}

int main() {
    Unit Unit1(1), Unit2(5), Unit3;
    Unit3 = Unit1 + Unit2;
    return 0;
}

 

 

13. Template

Template

  • Template은 특정 type에 의존하지 않는 코드를 작성하는 것을 포함한 generic programming의 기반임
  • ex) vector → vector<int>, vector<float>
  • Function, class를 정의하는 데 template 사용할 수 있음

Function Template

  • Function template 자체는 type, function, entity 등이 아님
  • Template definition만 포함하는 소스파일에서는 코드가 생성되지 않음
  • 코드가 생성되도록 하려면 template을 instantiate(인스턴스화) 해야 함
    • 컴파일러가 실제 함수 생성할 수 있도록 template argument 정해야 함
template <typename T>
return_type function_name(parameter list) {
    // body of function
}

1) Function Template 사용하지 않았을 때

#include <iostream>
#include <string>

using namespace std;

int user_abs(int a) {
    int ret;
    ret = a < 0 ? -a : a;
    cout << "processing abs: " << ret << endl;
    return ret;
}

float user_abs(float a) {
    float ret;
    ret = a < 0 ? -a : a;
    cout << "processing abs: " << ret << endl;
    return ret;
}

double user_abs(double a) {
    double ret;
    ret = a < 0 ? -a : a;
    cout << "processing abs: " << ret << endl;
    return ret;
}

int main() {
    int x1 = 10;
    float x2 = -10.1f;
    double x3 = -2.3;

    user_abs(x1);
    user_abs(x2);
    user_abs(x3);

    return 0;
}

2) Function Template 사용했을 때

#include <iostream>
#include <string>

using namespace std;

template <typename T>

T user_abs(T a) {
    T ret;
    ret = a < 0 ? -a : a;
    cout << "processing abs: " << ret << endl;
    return ret;
}

int main() {
    int x1 = 10;
    float x2 = -10.1f;
    double x3 = -2.3;

    user_abs(x1);
    user_abs(x2);
    user_abs(x3);

    return 0;
}

Template Class

  • Template function과 비슷하게 template class도 정의될 수 있음
  • 키워드 'class' 또는 'typename' 사용
template <class T>
class class_name {
};

class_name<type> obj_name;

Member Function

  • Class 밖에서 member function 정의하는 경우, 각 member function 앞에 template 키워드 작성해야 함
  • Class의 membership을 나타낼 때, template class임을 명시적으로 표시해야 함
template <typename T>
class class_name {
    fuc1(T a);
};
...
template <typename T>
T class_name<type>::fuc1(T a)