C++~inheritance

1. The concept and definition of inheritance

1.1 The concept of inheritance

Inheritance (inheritance) mechanism is the most important means for object-oriented programming to make code reusable . It allows programmers to expand, add functions, and generate new classes on the basis of maintaining the characteristics of the original class, called derived classes. (subclass) . Inheritance presents the hierarchical structure of object-oriented programming, reflecting the cognitive process from simple to complex. Inheritance is the reuse of class design hierarchy

class Person           //父类
{
    
    
public:
	void printf()
	{
    
    
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:
	string _name = "pater"; //姓名
	int _age = 18;   //年龄
};


class Student : public Person            //子类继承父类
{
    
    

protected:
	int _stuid = 0;  //学号
};

class Teacher : public Person           //子类继承父类
{
    
      

protected:
	int _jobid = 0;  //工号
};
int main()
{
    
    
	Student s;
	Teacher t;

	s.printf();
	t.printf();
	return 0;

}

1.2 Inheritance definition

1.2.1 Define format

The above code can see that the Person class is the parent class (base class), and the Student class is the subclass (derived class)
insert image description here

1.2.2 Inheritance and access qualifiers

insert image description here

1.2.3 Changes in access methods of inherited base class members

insert image description hereBase class private members are not visible in derived classes no matter how they are inherited. Invisibility here means that the private members of the base class are still inherited into the derived class object, but the derived class object is grammatically restricted from being able to access it no matter inside or outside the class.

If the base class member does not want to be directly accessed outside the class, but needs to be accessible in the derived class, it is defined as protected. It can be seen that the protected member qualifier appears because of inheritance

In practice, public inheritance is generally used, protected/private inheritance is rarely used , and the use of protected/private inheritance is not advocated, because protected/private inherited members can only be used in derived classes. In practice, Extended maintenance is not strong

class Person
{
    
    
public :
	 void Print ()
	 {
    
    
	 	cout<<_name <<endl;
	 }
protected :
 	string _name ; // 姓名
private :
 	int _age ; // 年龄
};
//class Student : protected Person
//class Student : private Person
class Student : public Person
{
    
    
protected :
 	int _stunum ; // 学号
};

2. Base class and derived class object assignment conversion

  • Objects of derived classes can be assigned to objects of base classes/pointers of base classes/references of base classes . There is a figurative term here called slicing or cutting. It means to cut the parent class part of the derived class and assign it to the past.
  • Base class objects cannot be assigned to derived class objects
  • A pointer to a base class can be assigned to a pointer to a derived class by casting
    insert image description here
//子类对象向父类对象赋值会发生切片
class Person
{
    
    
protected:
	string _name; // 姓名
	string _sex; // 性别
	int _age; // 年龄
};
class Student : public Person
{
    
    
public:
	int _No; // 学号
};

int main()
{
    
    
	Student s;
	Person p = s;    //子类对象可以赋值给父类对象/引用/指针
	Person* pp = &s;
	Person& rp = s;

	// s = p;    // 基类对象不能给子类对象赋值

	pp = &s;
	Student* ps1 = (Student*)pp;   //强转类型之后可以赋值
}

3. Scope in inheritance

  1. In the inheritance system, the base class and the derived class have independent scopes
  2. There are members with the same name in the subclass and the parent class, and the subclass members will block the direct access of the parent class to the members with the same name . This situation is called hiding , and it is also called redefinition (in the subclass member function, you can use the base class::base class member display access )
  3. It should be noted that if it is a hidden member function, only the same function name is required to constitute a hidden function
  4. Note that in practice it is best not to define members with the same name in the inheritance hierarchy .
//子类中的成员与父类的成员名称相同,会构成父类成员隐藏也叫重定义
class Person
{
    
    
protected:
	string _name = "小李子"; // 姓名
	int _num = 111; // 身份证号
};

class Student : public Person
{
    
    
public:
	void Print()
	{
    
    
		cout << " 姓名:" << _name << endl;
		cout << " 身份证号:" << Person::_num << endl;   
		           //这里要指明是父类作用域中的_num,不然会隐藏
		cout << " 学号:" << _num << endl;
	}
protected:
	int _num = 999; // 学号
};

int main()
{
    
    
	Student s1;
	s1.Print();
	return 0;
}
//子类中的成员函数名和父类函数名相同也会造成父类的成员函数隐藏
class A
{
    
    
public:
	void fun()
	{
    
    
		cout << "func()" << endl;
	}
};
class B : public A
{
    
    
public:
	void fun(int i)  //这里会对父类的fun造成隐藏
	{
    
    
		A::fun();   //用父类显示调用
		cout << "func(int i)->" << i << endl;
	}
};
int main()
{
    
    
	B b;
	b.fun(1);

	return 0;
}

Fourth, the default member function of the subclass

  1. Constructor of the subclass: call the constructor of the base class to initialize the part of the members of the base class. If the base class does not have a default constructor , it must be called explicitly during the initializer list phase of the derived class constructor
  2. Copy constructor of the derived class: call the copy construction of the base class to complete the copy initialization of the base class
  3. Operator= of the derived class: call the operator= of the base class to complete the copy of the base class
  4. The destructor of the derived class: After being called, the destructor of the base class is automatically called to clean up the members of the base class (although the destructors of the derived class and the base class are hidden, because the name of the destructor after compilation is Destory, this is to ensure cleanup order)
  5. Derived class object initialization first calls the base class construction and then calls the derived class construction
  6. Derived class object destructor cleanup first calls the derived class destructor and then adjusts the base class destructor
    insert image description here
//子类的默认成员函数
class Person
{
    
    
public:
	Person(const char* name = "peter")
		: _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 num)
		:Person(name)             //显示调用基类的构造函数
		,_num(num)
	{
    
    
	}
	Student(const Student& s)
		: Person(s)        //显示调用基类的拷贝构造函数
		, _num(s._num)
	{
    
    
		cout << "Student(const Student& s)" << endl;
	}
	Student& operator = (const Student& s)
	{
    
    
		cout << "Student& operator= (const Student& s)" << endl;
		if (this != &s)
		{
    
    
			Person::operator =(s);
			_num = s._num;
		}
		return *this;
	}
	~Student()
	{
    
    
		cout << "~Student()" << endl;  
	}


protected:
	int _num; //学号
};

int main()
{
    
    
	Student s1("jack", 17);
	Student s2(s1);
	Student s3("rose", 18);
	s1 = s3;
	return 0;
}

5. Inheritance and friendship

Friend relationships cannot be inherited , that is to say, base class friends cannot access subclass private and protected members

//基类的友元不能被子类继承
class Student;
class Person
{
    
    
public:
	friend void Display(const Person& p, const Student& s);
protected:
	string _name; // 姓名
};
class Student : public Person
{
    
    
protected:
	int _stuNum = 0; // 学号
};

void Display(const Person& p, const Student& s)
{
    
    
	cout << p._name << endl;    //可以访问
	//cout << s._stuNum << endl;  //不能访问
}

int main()
{
    
    
	Person p;
	Student s;
	Display(p, s);

	return 0;
}

6. Inheritance and static members

If the base class defines a static static member, there is only one such member in the entire inheritance system . No matter how many subclasses are derived, there is only one static member instance

//基类的static成员,就算被继承,也只有一个
class Person
{
    
    
public:
	Person() {
    
     ++_count; }
protected:
	string _name; // 姓名
public:
	static int _count; // 统计人的个数。
};
int Person::_count = 0;

class Student : public Person
{
    
    
protected:
	int _stuNum; // 学号
};

class Graduate : public Student
{
    
    
protected:
	string _seminarCourse; // 研究科目
};
int main()
{
    
    
	Student s1;   //会调用父类的构造函数
	Student s2;
	Student s3;
	Graduate g1;
	cout << " 人数 :" << Person::_count << endl;  // 4 因为调用了4次父类的构造函数
	Student::_count = 0;
	cout << " 人数 :" << Person::_count << endl; // 0   
	//因为静态成员是共享一份的,局部修改就全局改变
}

7. Complex rhombus inheritance and rhombus virtual inheritance,

7.1 Diamond inheritance and virtual inheritance

Single inheritance: When a subclass has only one direct parent class, this inheritance relationship is called single inheritance
insert image description here
Multiple inheritance: When a subclass has two or more direct parent classes, this inheritance relationship is called multiple inheritance
insert image description here
Diamond inheritance: Diamond inheritance is multiple inheritance a special case
insert image description here

The problem of diamond inheritance : Diamond inheritance has the problem of data redundancy and ambiguity. There will be two copies of the Person member in the Assistant object.

class Person
{
    
    
public:
	string _name; // 姓名
};

class Student : public Person
{
    
    
protected:
	int _num; //学号
};

class Teacher : public Person
{
    
    
protected:
	int _id; // 职工编号
};

class Assistant : public Student, public Teacher
{
    
    
protected:
	string _majorCourse; // 主修课程
};

int main()
{
    
    
	Assistant a;
	//a._name = "peter";       //error 会发生二义性, Assistant::_name不明确

	// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
	a.Student::_name = "xiaowang";
	a.Teacher::_name = "xiaoli";

	return 0;
}

Virtual inheritance can solve the problem of ambiguity and data redundancy of diamond inheritance. As in the inheritance relationship above, the problem can be solved by using virtual inheritance when the Student and Teacher inherit Person. It should be noted that virtual inheritance should not be used in other places

//用虚继承来解决数据冗余的问题
class Person
{
    
    
public:
	string _name; // 姓名
};
class Student : virtual public Person   //在继承处用virtual关键字,完成虚继承
{
    
     
protected:
	int _num; //学号
};
class Teacher : virtual public Person  //在继承处用virtual关键字,完成虚继承
{
    
    
protected:
	int _id; // 职工编号
};
class Assistant : public Student, public Teacher
{
    
    
protected:
	string _majorCourse; // 主修课程
};
int main()
{
    
    
	Assistant a;
	a._name = "lisi";   //解决了数据冗余,自然就解决了二义性问题

}

7.2 The principle of virtual inheritance

class A
{
    
    
public:
	int _a;
};

class B : virtual public A
//class B : public A
{
    
    
public:
	int _b;
};

class C : virtual public A
//class C: public A
{
    
    
public:
	int _c;
};

class D : public B, public C
{
    
    
public:
	int _d;
};

int main()
{
    
    
	D d;
	d.B::_a = 1;  //不是虚拟继承时,会单独改变作用域中的_a
	d.C::_a = 2;  // 虚拟继承之后,会修改所有的_a,可以证明所有子类的_a是同一个
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

Before virtual inheritance

insert image description here
After virtual inheritance
insert image description here

Here is a table pointed to by two pointers of B and C. These two pointers are called virtual base table pointers, and these two tables are called virtual base tables. The offset stored in the virtual base table. The A below can be found by the offset.

insert image description here

8. Inheritance and composition

//继承和组合
class A
{
    
    
public:
	void func()
	{
    
    }
protected:
	int _a;
};

//B继承A,可以复用A
class B : public A
{
    
    

protected:
	int _b;
};

//C组合A,也可以复用A
class C
{
    
    
private:
	int _c;
	A _a;
};
  1. Prefer object composition over class inheritance .

  2. In the inheritance mode, the internal details of the base class are visible to the subclasses . Inheritance destroys the encapsulation of the base class to a certain extent , and the change of the base class has a great impact on the derived class. The dependency relationship between the derived class and the base class is very strong, and the coupling degree is high

  3. Object composition is an alternative to class inheritance for reuse. New and more complex functions can be obtained by assembling or combining objects. Object composition requires that the objects being composed have well-defined interfaces . There is no strong dependency relationship between composite classes , and the degree of coupling is low . Preferring object composition helps you keep each class encapsulated

  4. In practice, use as many combinations as possible. The coupling degree of the combination is low, and the code maintainability is good. However, inheritance is also useful. Some relationships are suitable for inheritance, so use inheritance. In addition, to achieve polymorphism, inheritance is also necessary. The relationship between classes can use inheritance, you can use combination, use combination.

Guess you like

Origin blog.csdn.net/weixin_54792212/article/details/124205334