유도 클래스의 대입 연산자에는 아무런 명시를 하지 않으면, 기초 클래스의 대입 연산자가 호출되지 않는다. 유도 클래스의 대입 연산자 정의에서, 명시적으로 기초 클래스의 대입 연산자 호출문을 삽입하지 않으면, 기초 클래스의 대입 연산자는 호출되지 않아서, 기초 클래스의 멤버변수는 멤버 대 멤버의 복사 대상에서 제외된다.
이니셜라이저를 이용하면, 선언과 동시에 초기화가 이루어지는 형태로 바이너리 코드가 생성된다. 이 과정에서 초기화의 과정을 단순화 시키고, 성능향상을 기대할 수 있다.
C, C++의 기본 배열은 '경계검사를 하지 않는다'라는 단점이 있다. 이러한 단점 또한, 연산자 오버로딩을 통해, 어느정도 해결이 가능하다. 즉, [] 또한 연산자이고, 이 [] 연산자의 오버로딩을 통해 안전하지 않은 코드는 사전에 차단할 수 있다.
int& operator[] (int idx)
{
// 조건문
}
const의 선언유무도 함수 오버로딩의 조건에 해당한다. 가령, 위와 같이 배열 오버로딩을 한 경우, 만일 클래스에 ShowAllData와 같이 배열 내의 모든 숫자를 보여주는 멤버함수가 있다고 가정하자, 그 경우, 해당 함수는 const로 선언 될 것이다. (const로 선언하지 말아야 할 이유가 없다.) 이 경우 배열 오버로딩이 된 객체는 const를 참조할 수 없고, 따라서 ShowAllData를 호출하면 컴파일 에러가 발생한다.
이러한 경우를 방지하기 위해, 객체함수로 const 선언을 한 연산자 오버로딩 함수를 다시금 오버로딩 하여 호출하면, 컴파일 에러가 발생하지 않는다.
추가적으로, 배열을 오버로딩 할 때, 주소 값을 저장하는 경우 깊은 복사 혹은 얕은 복사를 신경쓰지 않아도 된다.
New/Delete
New와 Delete는 엄연한 연산자이다. 따라서 둘 모두 연산자 오버로딩이 가능하다.
New의 역할은 다음과 같다.
메모리 공간의 할당
생성자의 호출
할당하고자 하는 자료형에 맞게 반환된 주소 값의 형변환
따라서, 자료형을 사전에 정의해야 하는 malloc와 달리, new는 이러한 과정을 알아서 처리해준다. 또한 이 과정에서, 메모리 공간의 할당만 오버로딩이 가능하다.
void * operatornew(size_t size){ ... }
할당 형식은 위와 같고, 조건은 다음과 같다.
반환형이 반드시 void 형일 것
매개변수형은 size_t일 것, 이때 크기정보는 바이트 단위로 계산되어야 한다.
delete 연산자는 다음과 같이 오버로딩이 가능하다.
voidoperatordelete(void * adr){
delete adr;
}
operator new 와 operator delete는 static으로 선언된 함수이다. 따라서 이들은 다음과 같이 객체 생성 과정에서 호출이 가능하다.
Point * ptr = newPoint(10,20);
포인터 연산자
포인터를 기반으로 하는 모든 연산자를 포인터 연산자라 하며, 대표적인 포인터 연산자는 다음과 같다.\
-> 포인터가 가리키는 객체의 멤버에 접근
* 포인터가 가리키는 객체에 접근
이러한 연산자는 일반적인 연산자의 오버로딩과 크게 차이는 없지만, 한가지 차이점이 있다. 그것은 둘 다 피 연산자가 하나인 단항 연산자의 형태로 오버로딩 된다는 특징을 가진다.
unique_ptr<Song> SongFactory(const std::wstring& artist, const std::wstring& title){
// Implicit move operation into the variable that stores the result.return make_unique<Song>(artist, title);
}
voidMakeSongs(){
// Create a new unique_ptr with a new object.auto song = make_unique<Song>(L"Mr. Children", L"Namonaki Uta");
// Use the unique_ptr.
vector<wstring> titles = { song->title };
// Move raw pointer from one unique_ptr to another.
unique_ptr<Song> song2 = std::move(song);
// Obtain unique_ptr from function that returns by value.auto song3 = SongFactory(L"Michael Jackson", L"Beat It");
}
voidSongVector(){
vector<unique_ptr<Song>> songs;
// Create a few new unique_ptr<Song> instances// and add them to vector using implicit move semantics.
songs.push_back(make_unique<Song>(L"B'z", L"Juice"));
songs.push_back(make_unique<Song>(L"Namie Amuro", L"Funky Town"));
songs.push_back(make_unique<Song>(L"Kome Kome Club", L"Kimi ga Iru Dake de"));
songs.push_back(make_unique<Song>(L"Ayumi Hamasaki", L"Poker Face"));
// Pass by const reference when possible to avoid copying.for (constauto& song : songs)
{
wcout << L"Artist: " << song->artist << L" Title: " << song->title << endl;
}
}
shared_ptr
둘 이상의 소유자가 메모리에 있는 개체의 수명을 관리하는 시나리오를 위해 디자인된 스마트포인터
// shared_ptr-examples.cpp// The following examples assume these declarations:#include<algorithm>#include<iostream>#include<memory>#include<string>#include<vector>structMediaAsset
{virtual ~MediaAsset() = default; // make it polymorphic
};
structSong :public MediaAsset
{
std::wstring artist;
std::wstring title;
Song(const std::wstring& artist_, const std::wstring& title_) :
artist{ artist_ }, title{ title_ } {}
};
structPhoto :public MediaAsset
{
std::wstring date;
std::wstring location;
std::wstring subject;
Photo(
const std::wstring& date_,
const std::wstring& location_,
const std::wstring& subject_) :
date{ date_ }, location{ location_ }, subject{ subject_ } {}
};
usingnamespace std;
intmain(){
// The examples go here, in order:// Example 1// Example 2
}
// Use make_shared function when possible.auto sp1 = make_shared<Song>(L"The Beatles", L"Im Happy Just to Dance With You");
// Ok, but slightly less efficient. // Note: Using new expression as constructor argument// creates no named variable for other code to access.shared_ptr<Song> sp2(new Song(L"Lady Gaga", L"Just Dance"));
// When initialization must be separate from declaration, e.g. class members, // initialize with nullptr to make your programming intent explicit.shared_ptr<Song> sp5(nullptr);
//Equivalent to: shared_ptr<Song> sp5;//...
sp5 = make_shared<Song>(L"Elton John", L"I'm Still Standing");
//Initialize with copy constructor. Increments ref count.autosp3(sp2);
//Initialize via assignment. Increments ref count.auto sp4 = sp2;
//Initialize with nullptr. sp7 is empty.shared_ptr<Song> sp7(nullptr);
// Initialize with another shared_ptr. sp1 and sp2// swap pointers as well as ref counts.
sp1.swap(sp2);
weak_ptr
하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근은 허용, 하지만 소유자에는 포함되지 않는 스마트 포인터이다.
이는 참조횟수를 기반으로 동작하기에, 위와 같은 동작이 가능하다.
펑터(functor)
() 연산자를 이용하면, 객체를 함수처럼 사용할 수 있다. 이러한 클래스를 펑터 혹은 함수 오브젝트라고 한다.