[C++] Class의 개념 및 구성 요소(static, constructor/destructor, copy/move)
Class란?
class Triangle{
double sideA;
double sideB;
double sideC;
public:
double perimeter();
}
double Trangle::perimeter(){ // object의 reference point가 자동으로 넘어감
return sideA + sideB + sideC; // 따라서 class 속 변수들 바로 사용 가능
}
int main(void){
Triangle t1;
double p1;
p1 = t1.perimeter()
}
- C의 structure의 확장 버전
- var 뿐만 아니라 행동(function)까지 포함하여 object로 사용
- hierarchy(계층화된) programming 가능
- well-defined interfaces
- object의 blueprint(설계도)
- class로 생성한 실체가 object
Access Specifier
class에서 변수와 메소드 정의 시, 적근 가능 범위 설정
- private(default) : 해당 클래스의 method에서만 호출 가능
- protected : 해당 클래스 혹은 이를 상속한 subclass에서만 호출 가능
- public : anywhere : 클래스 밖(ex main 함수)에서도 호출 가능
Member : Variable & Method
- class의 member는 크게 variable과 method로 나눌 수 있다.
- methods : Class의 Member인 function
- method는 클래스 이름과 붙어서 사용된다.
- 선언문에서 : 클래스이름::method이름()
- 일반 object 속 함수 호출 : 클래스이름.method이름()
- pointer object 속 함수 호출 : 클래스이름→method이름()
- method는 클래스 이름과 붙어서 사용된다.
Special Variable : Static Members
- 상수
- static member는 class안에선 선언만 하고, 값 지정은 class 밖에서 해야한다.
- static memebr는 object에서 따로 선언하지 않아도 사용 가능하다.
- static memebr는 class 이름으로 바로 사용할 수 있다.
class Dummy{
static int n; //class안에선 선언만
};
int Dummy::n=0; //값 지정은 class 밖에서 해야한다.
int main(){
Dummy a;
cout << a.n << '\n'; //static memebr는 object에서 따로 선언하지 않아도 사용 가능하다.
cout << Dummy::n << '\n'; //static memebr는 class 이름으로 바로 사용할 수 있다.
}
Special Methods : Constructor/Destructor
- 사전 지식 : lvalue, rvalue
- Lvalue : 이름이 있는 object. Copy/Move 이후에도 접근 가능,
&
로 참조 -
Rvalue : 이름이 없는 object. Copy/Move 이후 접근 불가.
&&
로 참조vector<int> a = {1,2,3,4,5}; vector<int> b = a; // a, b는 lvalue, {1,2,3,4,5}는 rvalue
- std::move(a);
- Lvalue a를 Rvalue로 바꾸기
- 이후 더 이상 a가 필요없을 때만 사용
- Lvalue : 이름이 있는 object. Copy/Move 이후에도 접근 가능,
a. Constructor
- object 만들 때 자동 호출되는 특수 method로, constructor를 통해 object를 생성한다.
- class와 같은 이름을 가진다.
- 아무것도 return하지 않고, return type도 지정하지 않는다.
Triangle::Triangle(double a, double b, double c){
sideA = a;
sideB = b;
sideC = c;
}
Triangle t1(2.0, 2.0, 3.0); //static 선언
- initialization list
- constructor의 {} 속 내용이 실행되기 이전에 수행되는 리스트
- 상속에서 유용하게 쓰인다.
TTriangle::Triangle(double a, double b, double c) : sideA(a), sideB(b) { // side = A, side = B와 동일 sideC = c; }
- Default Constructor
- argument 없이 initialize하는 constructor
- 따로 constructor 정의 안 할 경우, 자동 생성
- 하나라도 다른 constructor를 선언할 경우, 자동 생성되지 않음
- 둘 다 쓰고 싶으면 overload되게 둘 다 써야함.
b. Destructor
- object 없어지기 직전에 자동으로 호출되는 특수 method
- class이름에 tilde(~)를 붙이고, argument는 없다.
~Triangle(void)
- Default Destructor
- no argument, no return
- 따로 Destructor 정의 안 할 경우, 자동 생성
- 클래스가 끝날 때, 그 클래스에 해당하는 모든 메모리를 비운다.
- member 중 클래스가 있으면 그 클래스의 destructor도 호출된다.
- 주로 pointer가 존재할 때, 사용자가 따로 선언할 필요가 생긴다.
- 포인터를 지우더라도 포인터가 가리키고 있는 주소의 값은 남기 때문이다.
c. Copy Constructor
- argument로 자신과 동일한 class의 object를 받는 constructor
- 들어온 object의 모든 내용을 복제한다
- 양쪽 object 모두 lvalue
-
Default Copy Constructor
class Example5{ Example5(const Example5& x){}; } Example5 foo; Example5 bar = foo;
- shallow copy가 일어난다.
- 단순히 value를 복사
- 문제점 : pointer를 복사 시, 동일한 주소를 두 object의 pointer가 모두 가리키게 되서 문제가 될 수 있다.
- shallow copy가 일어난다.
- Copy Constructor 선언
- Deep Copy를 하도록 선언할 수 있다.
- Deep Copy ↔ shallow copy
Example5(const Example5& x) : ptr(new string(x.content())) {}; Example5(const Example5& x) {ptr = new string(x.content())};
- Deep Copy를 하도록 선언할 수 있다.
d. Copy Assignment
- Copy Constructor가 있어서 수행할 수 있다.
- Copy Constructor vs Copy Assignment 차이
- Copy Constructor : 새로 object를 생성하면서 기존 object의 constructor와 값을 복사
- Copy Assignmnet : 두 object 실체가 있을 때, 한쪽의 값들을 복사
MyClass foo; MyClass bar; foo = bar;
- Operator Overloading이 가능해지는 원리이기도 하다.
e. Move Constructor/Move Assignment
- Copy Constructor/Assignmnet와 유사하되, 오른쪽이 rvalue(unnamed obejct)
- 실행된 이후엔 오른쪽 object는 사라진다.
- 대표적 예 : function의 return 값이 object이면, return 했을 때 이름이 없다.
MyClass fn();
MyClass bar = fn(); // Move Constructor
bar = MyClass(); //Move Assignment
- 선언 : Copy와 같은 구조이되, &가 2개가 되면 Move Constructor이다.
//deflaut move constructor
MyClass (MyClass && x); // argument로 들어온기존 object를 변형(비우기) 할 것이므로 const는 붙이지 않는 것으로 보임.
//선언
// move constructor
Example6 (Example6&& x) : ptr(x.ptr) {
x.ptr=nullptr;
};
// move assignment
Example6& operator= (Example6&& x) {
delete ptr; // pointer를 포함하는 new[] object를 assignment 할 때 한해서 필요 (아니어도 있어서 문제될 건 없음)
ptr = x.ptr;
x.ptr=nullptr; // move이니 기존 것 삭제
return *this;
};
- 장점 : Dynamic memory allocation의 경우, 단순히 pointer를 복사하는 것으로 수행할 수 있다.
- Cost가 큰 Copy를 수행하지 않아도 된다.
- 이는 argument를 call-by-value 대신 call-by-reference를 할 때의 장점과 같다.