개발자가 특정 함수를 호출하지 못하게 하려면 함수를 선언하지 않는 것이 가장 간단함
하지만 C++이 필요에 따라 자동으로 생성하는 함수는 같은 방법으로 해결할 수 없음
C++98에서는 해당 함수의 접근 지정자를 private으로 변경하여 호출을 방지했음 -> 비공개 함수
C++11에서는 함수의 선언 끝에 = delete;
를 붙여서 호출을 방지함 -> 삭제된 함수
(1) 삭제된 함수
// 비 멤버 함수에서 특정 형식의 함수 제거하기
bool isLucky(int number);
bool isLucky(char) = delete; // char 배제
bool isLucky(bool) = delete; // bool 배제
bool isLucky(double) = delete; // double, float 배제
(2) 비공개 함수
클라이언트 코드가 멤버 함수를 사용하려 할 때 C++은 먼저 그 함수의 접근성을 점검하고 그 후 삭제 여부를 점검함
삭제된 함수를 private으로 설정하는 경우 함수를 사용할 수 없는 주된 이유가 함수의 접근성이 되므로 오해의 여지를 제공함
class Base
{
public:
virtual void mf1() const;
virtual void mf2(int x);
virtual void mf3() &;
void mf4() const;
};
class Derived : public Base
{
public:
virtual void mf1(); // 부모 클래스와 달리 const 선언되지 않음
virtual void mf2(unsigned int x); // 부모 클래스와 달리 unsigned int를 받음
virtual void mf3() &&; // 부모 클래스와 달리 오른값으로 한정됨
void mf4() const; // 부모 클래스가 virtual로 선언되지 않음
};
override
키워드를 사용하면 재정의하려 한다는 의도를 명시적으로 표현할 수 있음
noexcept
키워드를 사용하여 예외를 던질 수 있는지 여부를 표기하는 방법
(1) 장점
다형성으로 인해 기반 클래스 포인터를 사용하여 파생 클래스의 객체를 조작할 수 있는데 이 때 정의된 제약 조건이 깨지면 프로그램의 안정성을 해치고 예외 처리를 어렵게 함
멤버 함수가 호출되는 객체(*this)의 왼값 버전과 오른값 버전을 다른 방식으로 처리할 수 있음
class Widget
{
public:
void doWork()& // *this가 왼값일 때 호출되는 함수
{
cout << "doWork() called on lvalue" << endl;
}
void doWork()&& // *this가 오른값일 때 호출되는 함수
{
cout << "doWork() called on rvalue" << endl;
}
};
Widget makeWidget()
{
return Widget();
}
int main()
{
Widget w; // 왼 값을 돌려주는 객체
w.doWork(); // Widget::doWork &를 호출함
makeWidget().doWork(); // Widget::doWork &&를 호출함
}