Effective C++ (6): Inheritance and Oject-Oritent Design
7853 단어 컴퓨터 기반
본 장 은 주로 상속 을 중심 으로 토론 을 전개한다.Public 상속 인지 private 또는 proctected 상속 인지,상속 중 virtual 의 확정 등 을 어떻게 확정 하 는 지,정 보 량 이 비교적 크다.
Rule 32: Make sure public inheritance models “is-a”
is-a 의 모든 관 계 를 만족 시 키 는 것 이 아니 라 Public 계승 을 사용 할 수 있 습 니 다.예 를 들 어 square is-a rectangle.그러나 모든 rectangle 에 적용 되 는 함수 가 square 에 적용 되 는 것 은 아 닙 니 다.이 럴 때 rectangle 을 변경 하여 더욱 일반화 시 키 거나 square 가 rectangle 을 계승 하지 못 하 게 하 십시오.
Remeber:"Public 계승"은"is-a"관 계 를 의미 하 며,base classes 에 적용 되 는 모든 일 은 derived classes 에 적용 된다.
Rule 33: Avoid hiding inherited names
virtual 함 수 는'인터페이스 계승'을 의미 하고 non-virtual 함 수 는'인터페이스 와 실현 이 모두 계승 되 어야 합 니 다'를 의미 합 니 다.
void Derived::mf4(){
...
mf2();
...
}
컴 파 일 러 가 함수 이름 을 찾 는 규칙 은 local 역할 영역 을 먼저 찾 은 다음 외곽 역할 영역(Derived Class)을 찾 은 다음 Base Class 를 찾 은 다음 namespace 까지 마지막 으로 전역 역할 영역 으로 이동 하 는 것 입 니 다.
그러나 과부하 함수 의 계승 에 대해 서 는 특별한 점 이 있 습 니 다.예 를 들 어:
class Base{
public:
virtual void mf1() = 0;
virtual void mf1(int);
virtual void mf2();
void mf3();
void mf3(double);
...
};
class Derived: public Base{
public:
virtual void mf1();
void mf3();
...
};
위의 코드 는 Derived class 에서 실 현 된 mf3 와 mf1 에서 리 셋 함 수 를 가 려 서 컴 파일 오류 가 발생 합 니 다.
Derived d;
d.mf1(1); //
d.mf3(1.0); //
따라서 리 셋 함수 에 대한 계승 은 하위 클래스 에서 using 또는 forwarding 을 사용 해 야 합 니 다.
class Derived: public Base{
public:
using Base::mf1;
using Base::mf3;
virtual void mf1();
void mf3();
...
};
// or
class Derived public Base{
public:
virtual void mf1(){
Base::mf1();
}
...
};
이렇게 하면 목적 을 달성 할 수 있다.
Remeber:
Rule 34: Differentiate between inheritance of interface and inheritance of implementation
하위 클래스 계승 이 원 하지 않 는 결 성 을 피하 기 위해 서 는 Pure virtual 함수 로 설명 하고 non-virtual 의 default Implement 를 정의 할 수 있 습 니 다.
class Airplane{
public:
virtual void fly(const Airport& dest) = 0;
...
protected:
void defaultFly(const Airport& dest);
};
class ModelA: public Airplane{
public:
virtual void fly(const Airport& dest){
defaultFly(dest);
}
...
};
이렇게 하면 사용자 가 무의식 적 인 상황 에서 부족 한 실현 을 계승 하 는 것 을 피 할 수 있다.Remeber:
어떤 때 는 virtual function 대신 비 virtual function 을 고려 할 수 있 습 니 다.의도 적 으로 사용 할 수 없 는 효과 가 있 습 니 다.
예 를 들 어 함수 지침 을 통 해 Strategy 모델 을 실현 하고 다음은 혈 액량 을 계산 하 는 코드 를 예 로 들 자.
class GameCharacter;
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter{
public:
typedef int (*HealthCalcFunc)(const GameCharacter&);
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc): healthFunc(hcf)
{}
int healthValue() const
{ return healthFunc(*this); }
private:
HealthCalcFunc healthFunc; // function pointer
};
이렇게 외부 삽입 함수 지침 을 통 해 주입(IoC)과 반전 제어(DI)에 의존 하 는 것 과 유사 합 니 다.사실 테스트 에 도 편리 합 니 다(GMock 등 도 구 를 잘 활용 할 수 있 습 니 다).
위의 코드 에 대해 서 는
tr1::function
로 교체 할 수 있 습 니 다.tr1:function 은 함수 포인터 class 로 호출 가능 한 모든 것(callable enity,즉 함수 포인터,함수 대상 또는 구성원 함수 포인터)을 호 환 할 수 있 습 니 다.위의 것 만 호 환 할 수 있 습 니 다.typedef int (*HealthCalcFunc)(const GameCharacter&);
다음으로 변경:
typedef std::tr1::function HealthCalcFunc;
됐 습 니 다.
Remeber:
Rule 36: Never redefine an inherited non-virtual function
계승 한 non-virtual 함 수 를 다시 정의 하지 마 십시오.같은 non-virtual 함수 에 대해 서 는 이치 에 따라 행동 이 같 기 때문에 그렇지 않 으 면 잘못된 의 미 를 일 으 키 기 쉽 습 니 다.행동 이 다 르 면 virtual 로 바 꾸 십시오.
Remeber:계 승 된 non-virtual 함 수 를 다시 정의 하지 마 십시오.
Rule 37: Never redefine a function’s inherited default parameter value
이것 은 매우 중요 한 규칙 입 니 다.결 성 된 매개 변수 값 은 모두 정적 으로 연결 되 어 있 습 니 다.즉,결 성 된 매개 변수 값 은 호출 자의 유형 에 따라 확 정 됩 니 다.예 를 들 어 다음 코드 와 같 습 니 다.
class Shape{
public:
virtual void print(int num = 1) const = 0;
};
class Rect: public Shape{
public:
virtual void print(int num = 2) const{
printf("%d
", num);
}
};
int main(){
Shape *p = new Rect;
p->print();
}
실제 출력 은 1 입 니 다.즉,기본 매개 변 수 는 Rect 의 num=2 가 아 닌 Shape 안의 num=1 입 니 다.그래서 virtual 동적 호출 함 수 를 통 해 호출 되 지만 정적 으로 연 결 된 매개 변수 입 니 다.각각 절반 씩 힘 을 내 서 완 료 된 이 작업 입 니 다.
따라서 가장 좋 은 방법 은 기본 매개 변수의 일 치 를 유지 하 는 것 입 니 다.기본 매개 변 수 는 계승 되 지 않 기 때문에 수 동 으로 일 치 를 유지 하고 하나의 수정 과 통일 적 인 수정 이 필요 합 니 다.또한 문 제 를 해결 하 는 방법 은 앞서 언급 한 NVI(non-virtual interface)기법 을 통 해 이 루어 집 니 다.Public interface 에서 기본 매개 변 수 를 설정 하 는 것 입 니 다.여기 서 는 군말 하지 않 습 니 다.
Remeber:계승 되 어 온 결 성 된 매개 변수 값 을 다시 정의 하지 마 십시오.결 성 된 매개 변수 값 은 모두 정적 으로 연결 되 어 있 고 virtual 함 수 는 동적 으로 연결 되 어 있 기 때 문 입 니 다.
Rule 38: Model “has-a” or “is-implemented-in-terms-of” through composition
Remeber:복합 을 통 해 has-a 또는'무언 가 에 따라 이 루어 진다'
Rule 39: Use private inheritance judiciously
Private 상속 은 Public 상속 에 비해 주로 두 가지 차이 가 있 습 니 다.
Remeber:
Rule 40: Use multiple inheritance judiciously
다 중 계승 에 있어 서 먼저 함수 명 은 나 쁜 의 미 를 일 으 키 기 쉽 습 니 다.계승 하 는 두 부모 클래스 에 같은 함수 명 이 있 을 때 사용 하 는 base class 의 함 수 를 밝 혀 야 합 니 다.
class BaseA{
public:
void check();
};
class BaseB{
public:
void check() const;
};
class Derived: public BaseA, public BaseB
{ ... };
Derived temp;
temp.check(); //
temp.BaseA::check(); //
'다이아몬드 형 다 중 상속'이 나 왔 을 때 다 중 상속 베이스 클래스 위 에 같은 베이스 클래스 가 공동으로 계승 되 었 기 때문에 가상 상속 으로 해결 해 야 한다.
class File { ... };
class InputFile: virtual public File { ... };
class OutputFile: virtual public File { ... };
class IOFile: public InputFile, OutputFile { ... };
그 러 니까
시리즈
Effective C++ (1): Accustoming Yourself to C++ Effective C++ (2): Constructors, Destructors, and Assignment Operators Effective C++ (3): Resource Management Effective C++ (4): Designs and Declaration Effective C++ (5): Implementation Effective C++ (6): Inheritance and Oject-Oritent Design Effective C++ (7): Templates and Generic Programming Effective C++ (8): Customizing new and delete Effective C++ (9): Miscellany
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
URL 입력에서 페이지 보이기까지3. 브라우저가 웹 서버에 HTTP 요청을 보낸다. 1. 사용자가 사이트 주소를 입력하고 브라우저가 DNS 조회를 시작하여 사용자에게 웹 페이지를 방문하도록 요청하면 DNS 서버(도메인 이름 해석 시스템)는 사용자가...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.