[C++] C++ overview
2023. 10. 11. 00:10ㆍRun/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(계층구조)
- Encapsulation (캡슐화)
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)