비공개 함수, 삭제된 함수, override

·2024년 12월 11일
0

C++

목록 보기
21/26

정의되지 않은 비공개 함수보다 삭제된 함수를 선호하라

개발자가 특정 함수를 호출하지 못하게 하려면 함수를 선언하지 않는 것이 가장 간단함
하지만 C++이 필요에 따라 자동으로 생성하는 함수는 같은 방법으로 해결할 수 없음

C++98에서는 해당 함수의 접근 지정자를 private으로 변경하여 호출을 방지했음 -> 비공개 함수
C++11에서는 함수의 선언 끝에 = delete; 를 붙여서 호출을 방지함 -> 삭제된 함수

비공개 함수와 삭제된 함수의 차이

(1) 삭제된 함수

  • 어떤 방법으로든 사용 불가 (멤버 함수나 friend에서도 접근 불가)
  • 어떤 함수도 삭제 가능 (비 멤버 함수, 템플릿 인스턴스 포함)
// 비 멤버 함수에서 특정 형식의 함수 제거하기
bool isLucky(int number);
bool isLucky(char) = delete;   // char 배제
bool isLucky(bool) = delete;   // bool 배제
bool isLucky(double) = delete; // double, float 배제

(2) 비공개 함수

  • 멤버 함수에만 적용 가능
  • 멤버 함수나 friend에서 접근 가능

삭제된 함수는 왜 public으로 선언하는 것이 관례일까?

클라이언트 코드가 멤버 함수를 사용하려 할 때 C++은 먼저 그 함수의 접근성을 점검하고 그 후 삭제 여부를 점검함
삭제된 함수를 private으로 설정하는 경우 함수를 사용할 수 없는 주된 이유가 함수의 접근성이 되므로 오해의 여지를 제공함

재정의 함수들을 override로 선언하라

재정의가 일어나기 위한 필수조건

  • 기반 클래스 함수가 반드시 가상 함수여야 함
  • 기반 함수와 파생 함수의 이름이 반드시 동일해야 함 (단, 소멸자는 예외)
  • 기반 함수와 파생 함수의 매개변수 형식들이 반드시 동일해야 함
  • 기반 함수와 파생 함수의 const성이 반드시 동일해야 함
  • 기반 함수와 파생 함수의 반환 형식과 예외 명세(exception specification)가 반드시 호환되어야 함
  • 멤버 함수들의 참조 한정자들이 반드시 동일해야 함
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 키워드를 사용하면 재정의하려 한다는 의도를 명시적으로 표현할 수 있음

추가 학습

예외 명세(exception specification)란?

noexcept 키워드를 사용하여 예외를 던질 수 있는지 여부를 표기하는 방법
(1) 장점

  • 컴파일러가 예외 처리와 관련된 최적화를 수행할 수 있음
  • 함수 인터페이스를 명확히하여 호출자가 외예 발생 여부를 쉽게 판단할 수 있음
  • 동적 조건을 넣어서 조건부로 적용될 수 있음

다형성으로 인해 기반 클래스 포인터를 사용하여 파생 클래스의 객체를 조작할 수 있는데 이 때 정의된 제약 조건이 깨지면 프로그램의 안정성을 해치고 예외 처리를 어렵게 함

멤버 함수 참조 한정자(reference qualifier)란?

멤버 함수가 호출되는 객체(*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 &&를 호출함
}

0개의 댓글

관련 채용 정보