[C++] 상속의 기본 기능(정의, 할당 변환, 친구, 정적 멤버, 가상 상속, 기본 멤버 함수, 범위)


1. 상속의 정의

이를 통해 프로그래머는 원래 클래스의 특성을 유지하면서 기능을 확장하고 추가할 수 있으므로 파생 클래스라고 하는 새 클래스를 생성할 수 있습니다.

1. 형식 정의

여기에 이미지 설명을 삽입하세요.
Person은 기본 클래스라고도 하는 상위 클래스입니다. Student는 파생 클래스라고도 하는 하위 클래스입니다.

2. 상속받은 기본 클래스 멤버의 접근 방식 변경

여기에 이미지 설명을 삽입하세요.
요약하다:

  1. 기본 클래스의 전용 멤버는 상속 방법에 관계없이 파생 클래스에 표시되지 않습니다 . 여기서 Invisible은 기본 클래스의 전용 멤버가 여전히 파생 클래스 객체에 상속되지만 구문은 파생 클래스 객체가 클래스 내부 또는 외부에서 액세스하지 못하도록 제한한다는 의미입니다.
    여기에 이미지 설명을 삽입하세요.

  2. 기본 클래스의 전용 멤버는 파생 클래스에서 액세스할 수 없으며 기본 클래스 멤버가 클래스 외부에서 직접 액세스하기를 원하지 않지만 파생 클래스에서 액세스해야 하는 경우 protected로 정의 됩니다 . 상속으로 인해 protected 멤버 한정자가 나타나는 것을 알 수 있다.

  3. 기본 클래스의 private 멤버는 하위 클래스에서 보이지 않으며, 하위 클래스에 있는 기본 클래스의 다른 멤버의 액세스 방법 == Min(기본 클래스의 멤버 액세스 한정자, 상속 방법), public > protected > private.

  4. class 키워드를 사용할 때의 기본 상속 방법은 private 이고, struct를 사용할 때의 기본 상속 방법은 public이지만 , 상속 방법을 명시적으로 작성하는 것이 가장 좋습니다.

  5. 실제로는 공개 상속이 일반적으로 사용되며 보호/비공개 상속은 거의 사용되지 않으며 보호/비공개 상속의 사용은 권장되지 않습니다.

2. 기본 클래스와 파생 클래스 객체의 할당 및 변환

1. 파생 클래스 객체는 기본 클래스 객체/기본 클래스 포인터/기본 클래스 참조에 할당될 수 있습니다. 여기에는 슬라이싱(Slicing), 커팅(Cutting)이라는 생생한 용어가 있습니다. 파생 클래스의 상위 클래스 부분을 잘라서 할당하는 것을 의미합니다.
2. 기본 클래스 객체는 파생 클래스 객체에 할당될 수 없습니다.
여기에 이미지 설명을 삽입하세요.
여기에 이미지 설명을 삽입하세요.

3. 상속의 범위

1. 상속 시스템에서는 기본 클래스와 파생 클래스가 독립적인 범위를 갖습니다.

2. 하위 클래스와 상위 클래스에 같은 이름을 가진 멤버가 있습니다.

하위 클래스와 상위 클래스에 같은 이름을 가진 멤버가 있는 경우 하위 클래스 멤버는 상위 클래스가 같은 이름을 가진 멤버에 직접 접근하는 것을 차단하는데, 이러한 상황을 숨기기(hiding), 재정의(redefinition)라고도 합니다. (하위 클래스 멤버 함수에서는 명시적 액세스를 위해 기본 클래스::기본 클래스 멤버를 사용할 수 있습니다)
여기에 이미지 설명을 삽입하세요.

3. 회원 기능 숨기기

숨겨진 멤버 함수인 경우 동일한 함수 이름만 있으면 숨겨진 함수를 구성할 수 있다는 점에 유의하세요.
여기에 이미지 설명을 삽입하세요.

4. 실제로는 상속 시스템에서 동일한 이름을 가진 멤버를 정의하지 않는 것이 가장 좋습니다.

4. 파생 클래스의 기본 멤버 함수

기본 클래스(상위 클래스):

class Person {
    
    
public:
	Person(const char*name)
		:_name(name)
	{
    
    
		cout << "Person()" << endl;
	}
	Person(const Person& p)
		:_name(p._name)
	{
    
    
		cout << "Person(const Person&p)" << endl;
	}
 
	Person& operator=(const Person& p) {
    
    
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p) {
    
    
			_name = p._name;
		}
		return *this;
	}

	~Person() {
    
    
		cout << "~Person()" << endl;
	}
protected:
	string _name;
};

파생 클래스(서브클래스)

class Student :public Person {
    
    
public:
	Student(const char*name="张三", int id = 0)
		//派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。
		:Person(name)
		,_id(id)
	{
    
    }

	Student(const Student& s) 
		// 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
		:Person(s)//切割
		,_id(s._id)
	{
    
    }

	Student& operator=(const Student& s) {
    
    
		//派生类的operator = 必须要调用基类的operator = 完成基类的复制
		if (this != &s) {
    
    
			Person::operator=(s);//发生切割
			_id = s._id;
		}
		return *this;
	}
		~Student()
	{
    
    
		// 析构函数的函数名被
		// 特殊处理了,统一处理成destructor

		// 显示调用父类析构,无法保证先子后父
		// 所以子类析构函数完成就,自动调用父类析构,这样就保证了先子后父
		 
		//析构函数:先析构子类后析构父类
		//构造函数:先构造父类后构造子类
	}

protected:
	int _id;
};

실행 결과:
여기에 이미지 설명을 삽입하세요.
요약:

  1. 파생 클래스의 생성자는 기본 클래스의 생성자를 호출하여 기본 클래스 멤버의 해당 부분을 초기화해야 합니다. 기본 클래스에 기본 생성자가 없는 경우 파생 클래스 생성자의 초기화 목록 단계 중에 명시적으로 호출해야 합니다.
  2. 파생 클래스의 복사 생성자는 기본 클래스의 복사 생성자를 호출하여 기본 클래스의 복사 초기화를 완료해야 합니다.
  3. 파생 클래스의 = 연산자는 기본 클래스의 = 연산자를 호출하여 기본 클래스의 복사본을 완성해야 합니다.
  4. 파생 클래스의 소멸자는 기본 클래스의 소멸자를 자동으로 호출하여 호출된 후 기본 클래스 멤버를 정리합니다. 이렇게 하면
    파생 클래스 개체가 파생 클래스 멤버를 먼저 정리한 다음 기본 클래스 멤버를 정리할 수 있기 때문입니다.
  5. 파생 클래스 개체 초기화에서는 기본 클래스 생성을 먼저 호출한 다음 파생 클래스 생성을 호출합니다.
  6. 파생 클래스 개체의 소멸자를 정리하려면 먼저 파생 클래스의 소멸자를 호출한 다음 기본 클래스의 소멸자를 호출합니다.

여기에 이미지 설명을 삽입하세요.

5. 상속과 우호

친구 관계는 상속될 수 없습니다. 즉, 기본 클래스 친구는 하위 클래스의 비공개 및 보호 멤버에 액세스할 수 없습니다.
여기에 이미지 설명을 삽입하세요.
정상적인 작업을 위해서는 파생 클래스도 친구를 추가해야 합니다.

6. 상속 및 정적 멤버

기본 클래스가 정적 멤버를 정의하는 경우 전체 상속 시스템에는 해당 멤버가 하나만 있습니다. 파생된 하위 클래스 수에 관계없이 정적 멤버 인스턴스는 하나만 있습니다.

여기에 이미지 설명을 삽입하세요.

7. 다이아몬드 가상 상속

1. 다이아몬드 상속

여기에 이미지 설명을 삽입하세요.
다이아몬드 상속 문제: 아래 개체 멤버 모델 구성에서 다이아몬드 상속에 데이터 중복성과 모호성 문제가 있음을 알 수 있습니다. Assistant 개체에는 Person 멤버의 복사본이 두 개 있습니다.
여기에 이미지 설명을 삽입하세요.

2.가상 상속

가상 상속은 다이아몬드 상속의 모호성과 데이터 중복 문제를 해결할 수 있습니다. 위의 상속 관계에서 볼 수 있듯이 학생과 교사가 Person을 상속받을 때 가상 상속을 사용하면 문제를 해결할 수 있습니다. 가상 상속은 다른 곳에서 사용해서는 안 된다는 점에 유의해야 합니다.
여기에 이미지 설명을 삽입하세요.

3. 마름모형 가상 상속의 원리:

class A
{
    
    
public:
 int _a;
};
// class B : public A
class B : virtual public A
{
    
    
public:
 int _b;
};
// class C : public A
class C : virtual public A
{
    
    
public:
 int _c;
};
class D : public B, public C
{
    
    
public:
 int _d;
};
int main()
{
    
    
 D d;
 d.B::_a = 1;
 d.C::_a = 2;
 d._b = 3;
 d._c = 4;
 d._d = 5;
 return 0;
}

1. 다이아몬드 상속의 메모리 분포

다음 그림은 다이아몬드 상속의 메모리 개체 멤버 모델입니다. 여기에서 데이터 중복성을 볼 수 있습니다.
여기에 이미지 설명을 삽입하세요.

2. 가상 상속 메모리 분배

다음 그림은 다이아몬드 가상 상속의 메모리 개체 멤버 모델입니다. 여기서는 A가 D 개체의 개체 구성에서 맨 아래에 배치되어 있음을 분석할 수 있습니다. 이 A는 B와 C 모두에 속합니다. 그러면 B와 C는 어떻게 찾나요? 일반적인 A?? 다음은 두 포인터 B와 C가 가리키는 테이블입니다. 이 두 포인터를 가상 기본 테이블 포인터라고 하며, 이 두 테이블을 가상 기본 테이블이라고 합니다. 가상 기본 테이블에 저장된 오프셋입니다. 아래 A는 오프셋으로 찾을 수 있습니다.
여기에 이미지 설명을 삽입하세요.
여기에 이미지 설명을 삽입하세요.
여기에 이미지 설명을 삽입하세요.

추천

출처blog.csdn.net/m0_74774759/article/details/132104793