C++다 중 계승 및 다 중 원리 실례 상세 설명

1.다 중 상속 의 이의 성 문제
예:

#include <iostream>
using namespace std;
class BaseA {
public:	void fun() { cout << "A.fun" << endl; }
};
class BaseB {
public:
	void fun() { cout << "B.fun" << endl; }
	void tun() { cout << "B.tun" << endl; }
};
class Derived :public BaseA, public BaseB {
public:
	void tun() { cout << "D.tun" << endl; }
	void hun() { fun(); } //         ,      
};
int main() {
	Derived d, * p = &d; d.hun();
	return 0;
}
유형 명 한정
void hun() { BaseA::fun(); } //상기 코드 의 14 번 째 줄 을 바 꾸 고 BaseA 클래스 이름 으로 호출 함 수 를 제한 합 니 다.
d.BaseB::fun(); //파생 클래스 대상 이 기본 클래스 동명 함 수 를 호출 할 때 클래스 이름 제한 을 사용 합 니 다.
p->BaseB::fun(); //파생 클래스 포인터 가 기본 클래스 동명 함 수 를 호출 할 때 클래스 이름 제한 을 사용 합 니 다.
이름 지배 규칙
만약 에 두 개 이상 의 관 계 를 포함 하 는 역할 영역 이 존재 한다 면 외층 은 하나의 이름 을 밝 혔 고 내층 은 같은 이름 을 다시 밝 히 지 않 으 면 외층 이름 은 내층 에서 볼 수 있다.내부 에서 같은 이름 을 밝 히 면 외부 이름 은 내부 에서 보이 지 않 습 니 다.숨겨 진 규칙 입 니 다.
유형의 파생 차원 구조 에서 기 류 의 구성원 과 파생 류 가 새로 추 가 된 구성원 은 모두 유형 작용 역 을 가지 고 이들 의 역할 역 이 다르다.기 류 는 외층 에 있 고 파생 류 는 내층 에 있다.파생 류 가 기본 멤버 와 같은 이름 의 새 멤버 를 밝 히 면 파생 류 의 새 멤버 는 기본 멤버 의 동명 멤버 를 차단 하고 멤버 명 을 직접 사용 하면 파생 류 에 새로 추 가 된 멤버 만 방문 할 수 있다.(기본 클래스 로부터 물 려 받 은 구성원 을 사용 하려 면 기본 클래스 이름 제한 을 사용 해 야 한다)

#include <iostream>
using namespace std;
class Base {
public:
	void fun() { cout << "A.fun" << endl; }
	Base(int x = 1, int y = 2) :x(x), y(y) {}
	int x, y;
};

class Derived :public Base{
public:
	void tun() { cout << "D.tun" << endl; }
	void fun() { cout << "D.fun" << endl; }
	Derived(int x = 0) :x(x) {}
	int x;
};
int main() {
	Derived d, * p = &d;
	d.fun();	//      	D.fun
	cout << p->x << " " << p->y << " " << p->Base::x << endl; //    0 2 1
	d.Base::fun(); //   	A.fun
}
2.가상 기류
가상 기류 의 사용 목적:간접 기 류 를 계승 할 때 한 명의 구성원 만 보류한다.
성명 가상 기본 클래스 는 파생 클래스 가 정 의 될 때 상속 방식 을 지정 할 때 성명 해 야 하 며,액세스 레이 블(Public,proctected,private 상속 방식)전에 virtual 키 워드 를 추가 해 야 합 니 다.주의:허 기 류 가 파생 류 에서 순서 만 계승 할 수 있 도록 이 기 류 의 모든 직접 파생 류 에서 허 기 류 로 성명 해 야 합 니 다.그렇지 않 으 면 여러 번 계승 할 수 있 습 니 다.
파생 류 는 직접 기 류 를 초기 화 하 는 것 뿐만 아니 라 허 기 류 를 초기 화 하 는 것 도 책임 져 야 한다.다 중 계승 에 가상 기류 가 없 으 면 파생 류 는 간접 기류 만 초기 화하 고 기류 에 대한 초기 화 는 각 간접 기류 에 의 해 이 루어 진다(이 로 인해 여러 기류 의 복사 본 이 각 간접 기류 에 저 장 될 수 있다).

#include <iostream>
using namespace std;
class Base {
public:
	Base(int n) { nv = n; cout << "Member of Base" << endl; }
	void fun() { cout << "fun of Base" << endl; }
private:
	int nv;
};
class A:virtual public Base {	//  Base    ,           virtual   
public:
	A(int a) :Base(a) { cout << "Member of A" << endl; }
private:
	int na;
};
class B :virtual public Base { //  Base    ,           virtual   
public:
	B(int b) :Base(b) { cout << "Member of B" << endl; }
private:
	int nb;
};
class Derived :public A, public B {
public:
	Derived(int n) :Base(n), A(n), B(n) { cout << "Member of Derived" << endl; }
  //             ,     Base     ,         A、B     
  //     Base         (      ),   Base                            (      )     ,     
private:
	int nd;
};
int main() {
	Derived de(3); de.fun();//       
	return 0;
}
가상 기류 에 대한 설명:
한 종 류 는 한 종족 에서 허 기 류 로 도 사용 할 수 있 고 비 허 기 류 로 도 사용 할 수 있다.
가상 기본 클래스 에 기본 구조 함수(또는 매개 변수 가 모두 기본 매개 변수)가 없 으 면 파생 클래스 에서 구조 함 수 를 명시 하고 초기 화 목록 에 가상 기본 구조 함수 에 대한 호출 을 표시 해 야 합 니 다.
한 구성원 초기 화 목록 에서 가상 기류 와 비 가상 기류 구조 함수 에 대한 호출 이 동시에 나타 날 때 가상 기류 의 구조 함수 가 비 가상 기류 의 구조 함수 보다 먼저 실 행 됩 니 다.
가상 함수
가상 함수 개념:virtual 키워드 에 의 해 수 식 된 구성원 함수,즉 가상 함수 로 그 역할 은 다 형 성 을 실현 하 는 것 입 니 다.
가상 함수 사용 설명:
가상 함 수 는 클래스 의 구성원 함수 일 뿐 정적 일 수 없습니다.
가상 키 워드 는 클래스 에서 만 사용 할 수 있 습 니 다.가상 함수 가 클래스 체 외 에서 정의 되 더 라 도 가상 키 워드 를 가 져 갈 수 없습니다.
파생 클래스 에서 기본 클래스 허 함수 와 같은 이름 의 구성원 함 수 를 정의 할 때 이 함수 의 매개 변수 개수,유형,순서 와 반환 유형 이 기본 클래스 와 완전히 일치 하면 파생 클래스 의 이 구성원 함 수 는 virtual 키 워드 를 사용 하 든 말 든 자동 으로 허 함수 가 됩 니 다.
가상 함 수 를 이용 하여 기본 클래스 와 파생 클래스 에서 같은 함수 명 정의 함수 의 서로 다른 실현 을 사용 하여'하나의 인터페이스,다양한 방식'의 목적 을 달성 할 수 있 습 니 다.기본 포인터 나 참조 가 가상 함수 에 접근 할 때 시스템 은 실행 시 포인터(또는 참조)가 가리 키 는 실제 대상 에 따라 호출 된 가상 함수 버 전 을 확인 합 니 다.
가상 함 수 를 사용 하 는 것 이 반드시 다 태 성 을 발생 시 키 는 것 도 아니 고 동적 연결 을 사용 하 는 것 도 아니다.예 를 들 어 호출 에서 가상 함수 에 대한 클래스 이름 제한 을 사용 하면 C++이 함수 에 대해 정적 연결 을 사용 하도록 강제 할 수 있 습 니 다.
파생 클래스 에서 기본 구성원 함 수 를 가리 키 는 포인터 가 가상 함 수 를 가리 키 고 대상 을 가리 키 는 기본 포인터(또는 참조)를 통 해 이 가상 함 수 를 방문 할 때 도 다 형 성 이 발생 합 니 다.

#include <iostream>
using namespace std;
class Base {
public:
	virtual void print() { cout << "Base-print" << endl; }
};
class Derived :public Base {
public:
	void print() { cout << "Derived-print" << endl; }
};
void display(Base* p, void(Base::* pf)()) {
	(p->*pf)();
}
int main() {
	Derived d; Base b;
	display(&d, &Base::print);	//  Derived-print
	display(&b, &Base::print);	//  Base-print
  return 0;
}
가상 함 수 를 사용 하면 시스템 은 일정한 공간 비용 을 증가 시 켜 가상 함수 표를 저장 해 야 하지만 시스템 은 동적 연결 을 할 때 시간 이 적 기 때문에 가상 함수 가 실현 하 는 다 형 성 은 효율 적 이다.
가상 함수 다 중 조건 실현(동시에 만족)
클래스 간 의 계승 관 계 는 할당 호 환 규칙 을 만족 시 킵 니 다.
같은 이름 의 허 함 수 를 바 꾸 었 으 나 함수 형 삼,반환 유형 은 일치 해 야 합 니 다.
할당 호 환 규칙 에 따라 포인터(또는 참조)를 사용 합 니 다.
  • 기본 포인터(또는 참조)를 사용 하여 가상 함수 에 접근 합 니 다
  • 4.567917.포인터(또는 참조)를 함수 매개 변수 로 합 니 다.이 함 수 는 반드시 클래스 의 구성원 함수 가 아니 라 일반 함수 일 수 있 으 며 다시 불 러 올 수 있 습 니 다.
    가상 분석 함수
    파생 클래스 의 대상 이 메모리 에서 취 소 될 때 일반적으로 파생 클래스 의 분석 함 수 를 호출 한 다음 에 기본 클래스 의 분석 함 수 를 호출 합 니 다.그러나 new 연산 자 를 사용 하여 파생 클래스 대상 을 만 들 고 기본 클래스 의 포인터 가 이 대상 을 가리 키 는 것 을 정의 하면 delete 연산 자 를 사용 하여 대상 을 취소 할 때 시스템 은 기본 클래스 의 분석 함수 만 실행 하고 파생 클래스 의 분석 함 수 를 실행 하지 않 기 때문에 파생 클래스 대상 을 진정 으로 취소 할 수 없습니다.
    delete 키워드 가 기본 포인터 에 작용 하 기 를 원할 때 파생 클래스 의 분석 함 수 를 실행 하려 면 기본 클래스 의 분석 함 수 를 가상 함수 로 설명 해 야 합 니 다.
    기본 클래스 의 석조 함 수 를 가상 함수 로 설명 하면 이 기본 클래스 에서 파생 된 모든 파생 클래스 의 석조 함수 도 자동 으로 가상 함수 가 됩 니 다.파생 클래스 의 석조 함수 와 기본 클래스 의 석조 함수 이름 이 다 르 더 라 도.
    C++는 가상 구조 함 수 를 지원 하지만 가상 구조 함 수 는 지원 되 지 않 습 니 다.즉,구조 함 수 는 가상 함수 로 설명 할 수 없습니다!
    순 허 함수
    많은 상황 에서 기본 클래스 에서 허 함수 에 의미 있 는 정 의 를 내 릴 수 없다.이 때 는 이 를 순 허 함수 로 설명 하고 구체 적 인 정 의 를 파생 류 에 남 겨 둘 수 있다.순 허 함수 의 정의 형식 은:virtual 반환 형식 함수 이름(형식 매개 변수 목록)=0;
    순 허 함 수 를 포함 하 는 종 류 를 추상 류 라 고 하 는데 하나의 추상 류 는 기본 류 로 만 새로운 종 류 를 파생 시 킬 수 있 기 때문에 추상 류 라 고도 부 르 고 추상 류 는 대상(실체)을 정의 할 수 없다.
    4.다 태 성
    다 중 적 의미:같은 조작 이 서로 다른 대상 에 작용 할 때 서로 다른 결 과 를 나타 내 는 것 을 말한다.
    4.567917.과부하 다 형―함수 과부하,연산 자 과부하강제 다 태―유형 전환 이 라 고도 부른다C++의 기본 데이터 형식 간 전환 규칙:char→short→int→unsigned→long→unsigned→float→double→long double
  • 표현 식 에서 3 의 강제 형식 변환 표현 식 을 사용 할 수 있 습 니 다:staticcast(E)또는 T(E)또는(T)E 는 E 대표 연산 식(값 획득)이 고 T 는 유형 식별 자 를 대표 합 니 다.강제 다 형 은 유형 검 사 를 복잡 하 게 만 들 고 특히 과부하 가 허용 되 는 상황 에서 해소 할 수 없 는 이의 성 을 초래 할 수 있다
  • 유형 매개 변수 화 다 형―템 플 릿(함수 템 플 릿,클래스 템 플 릿)
  • 4.567917.다 형―사용 허 함수 포함최소한 하나의 가상 함 수 를 포함 하 는 클래스 를 다 중 클래스 라 고 하 는데,가상 함 수 는 프로그램 이 동적 연결 방식 으로 실행 결과 의 다 중 화 를 이 룰 수 있 게 한다.이러한 다 중 사용 배경 은 파생 류 가 기본 류 의 모든 조작 을 계승 하거나 기본 류 의 조작 은 파생 류 를 조작 하 는 대상 에 사 용 될 수 있다.기본 류 의 조작 이 파생 류 에 적응 하지 못 할 때 파생 류 는 기본 류 의 조작 을 다시 불 러 와 야 한다.이 는 C++기본 클래스 의 포인터 로 파생 클래스 의 주 소 를 받 거나 기본 클래스 의 참조 로 파생 클래스 의 대상 을 연결 할 수 있 도록 하 는 것 으로 나 타 났 다.
    정적 연결 과 동적 연결
    연결:모듈 이나 함 수 를 합 쳐 실행 가능 한 코드 를 만 드 는 처리 과정 을 만 들 고 각 모듈 이나 함수 에 메모리 주 소 를 할당 하 며 외부 방문 에 도 정확 한 메모리 주 소 를 할당 합 니 다.
    정적 컴 파일:컴 파일 단계 에서 함수 구현 과 함수 호출 바 인 딩.정적 연결 은 컴 파일 단계 에서 모든 함수 나 모듈 실행 에 필요 한 정 보 를 알 아야 합 니 다.함수 에 대한 선택 은 대상 을 가리 키 는 포인터(또는 참조)형식 을 기반 으로 합 니 다.C 언어 에서 모든 연결 은 정적 연결 이 고 C++에서 일반적인 상황 에서 의 연결 도 정적 연결 입 니 다.
    동적 연결:프로그램 이 실 행 될 때 만 함수 실현 과 함수 호출 을 하 는 연결 을 동적 연결(dynamic binding)이 라 고 합 니 다.
    
    #include <iostream>
    #define PI 3.14159265
    using namespace std;
    class Point {
    public:
    	Point(double x = 0, double y = 0) :x(x), y(y) {}
    	double area_static() { return 0; }	//     ,        ,      
    	virtual double area_dynamic() { return 0; } //      ,                ,     
    private:
    	double x, y;
    };
    class Circle :public Point {
    public:
    	Circle(double r = 1.0) :r(r) {} //                 ,                     
    	Circle(double x, double y, double r=1.0) :Point(x, y), r(r) {} //         、          
    	double area_static() { return PI * r * r; } //    
    	double area_dynamic() { return PI * r * r; } //    (     ),       ,     virutal   
    private:
    	double r;
    };
    int main() {
    	Point o(2.5, 2.5); Circle c(2.5, 2.5, 1);
    	Point* po = &o, * pc = &c, & y_c = c;
    //           ,               ,           ,         ,            
    	cout << "Point area =" << o.area_static() << endl;	//  0
    	cout << "Circle area=" << c.area_static() << endl;	//  3.14159
    	cout << "the o area from po:" << po->area_static() << endl; //  0
    	cout << "the c area from pc:" << pc->area_static() << endl;	//  0
    	cout << "the c area from cite y_c:" << y_c.area_static() << endl; //  0
    //         ,   (   )、   ,               vptr        	,           (      )         
    	cout << "the o area from po:" << po->area_dynamic() << endl; //  0
    	cout << "the c area from pc:" << pc->area_dynamic() << endl; //  3.14159
    	cout << "the c area from cite y_c:" << y_c.area_dynamic() << endl; //  3.14159
      //        
      cout << "the c area calculated by Point::area_():" << pc->Point::area_dynamic() << endl; //  0
    	return 0;
    }
    동적 연결 과 가상 함수
  • 가상 함 수 를 호출 할 때 먼저 vptr 포인터(가상 함 수 를 컴 파일 할 때 컴 파일 러 는 클래스 에 가상 함수 표를 가리 키 는 vptr 지침 을 자동 으로 생 성 합 니 다)를 통 해 가상 함수 표를 찾 은 다음 에 가상 함수 의 진정한 주 소 를 찾 아 호출 합 니 다
  • 4.567917.파생 류 는 기본 클래스 의 허 함수 표를 계승 할 수 있 고 기본 클래스 와 같은 이름(매개 변수 도 같 음)의 구성원 함수 라면 virtual 성명 을 사용 하 든 안 하 든 자동 으로 허 함수 가 됩 니 다.만약 파생 류 가 계승 기본 클래스 의 허 함 수 를 바 꾸 지 않 았 다 면 함수 포인터 가 기본 클래스 의 허 함 수 를 호출 합 니 다.파생 류 가 기본 클래스 의 가상 함 수 를 바 꾸 면 컴 파일 러 는 파생 클래스 의 가상 함수 로 주 소 를 다시 만 들 고 함수 지침 은 바 꾼 후의 가상 함 수 를 호출 합 니 다이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기