#include <iostream>
using namespace std;
class Example {
public:
Example() {
cout << "Example()" << endl;
}
Example(const Example &rhs) { // right hand side의 약자.
this -> data = rhs.data;
cout << "Example(const Example &)" << endl;
}
int GetData(void) const { return data; }
void SetData(int param) { data = param; }
private:
int data = 0;
}
int main(int argc, char* argv[]) {
// 디폴트 생성자가 호출되는 경우
Example a;
a.SetData(10);
// 복사 생성자가 호출되는 경우
Example b(a);
cout << b.GetData() << endl;
return 0;
}
void TestFunc(Example param) {
cout << "TestFunc()" << endl;
param.SetData(20);
}
void TestFunc(Example ¶m) {
cout << "TestFunc()" << endl;
param.SetData(20);
}
깊은 복사(Deep Copy): 복사에 의해 실제로 두 개의 값이 생성되는 것.
얕은 복사(Shallow Copy): 원본 값은 하나인데, 접근 포인터만 둘로 늘어나는 것.
얕은 복사에 의해 원본 데이터를 두 개 이상의 포인터가 참조하고 있는 경우, 어느 한 곳에서 delete
연산자를 통해 메모리를 해제하면 문제가 발생할 수 있다.
Example& operator=(const Example &rhs) {
*data = *rhs.data;
return *this;
}
class Example {
public:
Example(int param): data(param) {}
int GetData(void) const {
return data;
}
void SetData(int param) {
data = param;
}
private:
int data = 0;
}
void TestFunc(Example param) {
cout << param.GetData() << endl;
}
int main(int argc, char* argv[]) {
// TestFunc의 매개변수 타입은 Example이지만, Example 클래스의 변환 생성자에 의해 묵시적으로 형변환이 일어난다.
// 따라서 위 코드는 TestFunc(Example(5))와 같은 의미다.
// 변환 생성자에 explicit 예약어를 추가함으로써 묵시적인 형변환을 방지할 수 있다.
TestFunc(5);
return 0;
}
TestFunc(5)
를 호출하면 Example
타입의 임시 객체가 생성된 후 함수의 종료와 동시에 소멸된다.int
자료형이 Example
형식으로 변환될 수는 있으나, 반대의 경우는 불가능하다.class Example {
~~~
public:
operator int(void) { return data;}
~~~
}
int main(int argc, char* argv[]) {
Example a(10);
int data1 = (int)a; // C 스타일 변환으로, 되도록 사용하지 않는것이 권장됨. 형변환이 지원되지 않는 경우에도 강제로 형변환을 해버리기 때문.
int data2 = a;
int data3 = static_cast<int>(a); // C++에서 권장되는 형변환 연산. 형변환이 지원되지 않는 경우에 제약이 따른다.
return 0;
}
C++의 형변환 연산자로는 다음과 같은 것들이 있다.
const_cast
static_cast
dynamic_cast
reinterpret_cast
형변환 연산자에도 explicit
예약어를 적용할 수 있다.
#include <iostream>
class Example {
public:
Example() { cout << "디폴트 생성자" << endl; }
~Example() { cout << "소멸자" << endl; }
Example(const Example &rhs): data(rhs.data) {
cout << "복사 생성자" << endl;
}
Example(Example &&rhs): data(rhs.data) {
cout << "이동 생성자" << endl;
}
Example& operator=(const Example &) = default;
int GetData() const { return data; }
void SetData(int param) { data = param; }
private:
int data = 0;
}
Example TestFunc(int param) {
cout << "***TestFunc(): Begin***" << endl;
Example a;
a.SetData(param);
cout << "***TestFunc(): End***" << endl;
return a;
}
int main(int argc, char* argv[]) {
Example b;
cout << "*****Before*****" << endl;
b = TestFunc(20);
cout << "*****After******" << endl;
Example c(b);
return 0;
}
/*
출력 결과:
디폴트 생성자
*****Before*****
***TestFunc(): Begin***
디폴트 생성자
***TestFunc(): End***
이동 생성자
소멸자 -> TestFunc에서의 지역변수 a의 소멸
소멸자 -> TestFunc의 반환값을 b로 넘길 때 생기는 임시 객체의 소멸
*****After******
복사 생성자
소멸자 -> b의 소멸
소멸자 -> c의 소멸
*/