일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 영화 리뷰
- 오블완
- 예외
- effective stl
- universal reference
- 스마트 포인터
- virtual function
- lua
- c++
- Smart Pointer
- operator new
- 영화
- 게임
- 보편 참조
- effective modern c++
- 티스토리챌린지
- 상속
- Effective c++
- reference
- 암시적 변환
- implicit conversion
- 언리얼
- 참조자
- resource management class
- std::async
- UE4
- iterator
- exception
- more effective c++
- 반복자
Archives
- Today
- Total
스토리텔링 개발자
[Effective Modern C++] 12. override 키워드와 참조 한정사(reference qualifier) 본문
Effective C++/Effective Modern C++
[Effective Modern C++] 12. override 키워드와 참조 한정사(reference qualifier)
김디트 2025. 2. 20. 10:33728x90
항목 12. 재정의 함수들을 override로 선언하라
가상 함수 재정의
- 파생 클래스 함수를 기반 클래스의 인터페이스를 통해 호출할 수 있게 만드는 매커니즘
class Base
{
public:
virtual void doWork();
...
};
class Derived : public Base
{
public:
virtual void doWork();
...
};
std::unique_ptr<Base> upb = std::make_unique<Derived>();
...
upb->doWork(); // 기본 클래스의 인터페이스로 파생 클래스의 함수가 호출된다.
- 재정의를 위한 필수 조건
- 기본 클래스 함수가 반드시 가상함수여야 한다.
- 함수 이름이 반드시 동일해야 한다.(소멸제는 예외)
- 함수의 매개변수 타입이 반드시 동일해야 한다.
- 함수의 const 성이 반드시 동일해야 한다.
- 함수의 리턴 형식과 예외 명세(/exception specification)가 반드시 호환되어야 한다.
- C++11에 추가된 조건
- 함수의 참조 한정사(reference qualifier)가 반드시 동일해야 한다.
멤버 함수 참조 한정사(reference qualifier)
- 멤버 함수를 lvalue 혹은 rvalue에서만 사용할 수 있게 제한할 수 있다.
class Widget
{
public:
...
void doWork() &; // *this가 lvalue일 때만 적용된다.
void doWork() &&; // *this가 rvalue일 때만 적용된다.
};
Widget makeWidget(); // rvalue 리턴
Widget w; // lvalue
w.doWork(); // Widget::doWork & 버전 호출
makeWidget().doWork(); // Widget::doWork && 버전 호출
- 즉, const와 비슷한 용법으로 사용된다.
- lvalue에서만 사용해야 안전한 상황이 있을 수 있다.
class Widget
{
public:
using DataType = std::vector<double>;
...
DataType& data() { return values; }
...
private:
DataType values;
};
Widget w;
Widget makeWidget();
...
auto vals1 = w.data(); // std::vector<double>&가 적재된다.
auto vals2 = makeWidget().data(); // 마찬가지. 하지만 임시 객체의 참조이다!
- 참조 한정사를 사용하면 안전하게 사용할 수 있다.
class Widget
{
public:
using DataType = std::vector<double>;
...
DataType& data() & { return values; }
DataType& data() && { return std::move(values); }
...
private:
DataType values;
};
Widget w;
Widget makeWidget();
...
auto vals1 = w.data(); // & 버전이 호출된다.
auto vals2 = makeWidget().data(); // && 버전이 호출된다.
- overload 시에 조심할 것.
- 참조 한정사 버전이 있는데, 참조 한정사가 없는 버전을 오버로드하면 중의적인 호출이 될 수 있다.
재정의 실수 상황
- 의도와 다르게 행동해도 컴파일은 대개 성공한다.
- 컴파일러에 따라 경고가 발생할 수도 있고 아닐 수도 있다.
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); // 매개변수 타입이 달라서 재정의 실패
virtual void mf3() &&; // 참조 한정사가 달라서 재정의 실패
void mf4() const; // virtual이 붙지 않아서 재정의 실패
};
- 실수하기 너무 쉽기 때문에 override 키워드를 붙인다.
class Base
{
public:
virtual void mf1() const;
virtual void mf2(int x);
virtual void mf3() &;
virtual void mf4() const;
};
// 이제 의도대로 재정의한다.
class Derived : public Base
{
public:
virtual void mf1() const override;
virtual void mf2(int x) override;
virtual void mf3() & override;
void mf4() const override; // virtual을 붙이는 건 선택사항
};
리팩토링 시의 용이함
- override 키워드가 붙었을 때 기본 클래스의 함수 사양을 바꾸면 컴파일러는 경고해준다.
- 하지만, 그렇지 않다면 일일이 어떻게 찾아낼 것인가...
C++11의 컨텍스트 키워드(contextual keyword)
- C++11에서 final과 override가 추가되었다.
- 하지만, 함수 선언의 끝에 나올때만 의미를 가지므로 아래와 같은 상황은 굳이 처리해줄 필요 없다.
class Warning
{
public:
...
void override(); // override 키워드로 동작할 리 없으므로 놔둬도 무방
...
};
728x90
'Effective C++ > Effective Modern C++' 카테고리의 다른 글
[Effective Modern C++] 14. noexcept (0) | 2025.02.24 |
---|---|
[Effective Modern C++] 13. const_iterator 선호하기 (0) | 2025.02.21 |
[Effective Modern C++] 11. 삭제된 함수(deleted function) (0) | 2025.02.19 |
[Effective Modern C++] 10. enum class (0) | 2025.02.18 |
[Effective Modern C++] 9. typedef vs using (0) | 2025.02.17 |
Comments