Principles of Inheritance/Virtual Inheritance in C++

Inheritance in C++

1. The concept and definition of inheritance

Inheritance is an important way to improve the code reuse rate. It allows programmers to add other features and functions on the basis of maintaining the characteristics of the original class . Such classes are called derived classes. Inheritance is the reuse of class design levels .

class Person
{
public:
	void Print()
	{
		cout << "name: " << _name << endl;
		cout << "age: " << _age << endl;
	}
	
protected:
	string _name = "牡丹";
	int _age = 18;
};

class Student :public Person
{
protected:
	int _stuid;
};

class Teacher :public Person
{
protected:
	int _jobid;
};

int main(void)
{
	Student s;
	Teacher t;
	s.Print();
	t.Print();
	return 0;
}

The result of the operation is:

Obviously Student和Teacherthere are no functions in it Print(), why is it still running normally? Because they all inherit Personthe class.

1.1 Inheritance definition

Below we see that Person is the parent class, also known as the base class. Student is a subclass, also known as a derived class.

1.12 Inheritance Relationships and Access Qualifiers

class members/inheritance public inheritance protected inheritance private inheritance
public members of the base class public members of derived classes protected members of derived classes private members of derived classes
protected members of the base class protected members of derived classes protected members of derived classes private members of derived classes
private members of the base class Not visible (hidden) in derived classes Not visible (hidden) in derived classes Not visible (hidden) in derived classes

Summarize

1. The members of the base class privateare invisible and hidden in the derived class regardless of the inheritance method. Outside the class, they are privatemembers that cannot be called in the derived class and are hidden.

2. privateMembers cannot be accessed in derived classes, but if you want to be inaccessible outside the class, you can use them if they are accessed in derived classes protected.

3. public > protected > privateThe access method of other members of the base class in the subclass == the one with less authority

4. The default inheritance method when using the keyword class is private, structthe default inheritance method when using is public, but it is best to display

write out inheritance

5. In practice, inheritance is generally used , and inheritance publicbis rarely used , and the use of it is not advocated.protetced/private

protetced/privateInheritance, because protetced/privatethe inherited members can only be used in the class of the derived class, in practice

Extended maintenance is not strong.

2. Copy conversion of base class and derived class objects

  • Objects of derived classes can be assigned to objects of base classes/pointers of base classes/references of base classes . There is a very vivid saying called slicing or cutting. It is to cut and assign the value of the parent class in the derived class.

  • An object of a base class cannot be assigned to a derived class

  • A pointer to a base class can be assigned to a pointer to a derived class by casting. But only when the pointer of the base class points to the derived class object

    is safe. Here, if the base class is a polymorphic type, you can use RTTIthe dynamic_cast of (Run-Time Type Information) to

    Security transitions are performed after identification is performed.

class Person
{
protected:
	string _name; // 姓名
	string _sex; // 性别
	int _age; // 年龄
};
class Student : public Person
{
public:
	int _No; // 学号
};
void Test()
{
	Student sobj;
	// 1.子类对象可以赋值给父类对象/指针/引用
	Person pobj = sobj;//Person = Student
	Person* pp = &sobj;//Person = Student
	Person& rp = sobj;//Person = Student

	//2.基类对象不能赋值给派生类对象
	sobj = pobj;//Student = Person

	// 3.基类的指针可以通过强制类型转换赋值给派生类的指针
	pp = &sobj;
	Student * ps1 = (Student*)pp; // 这种情况转换时可以的。Student* = (Student*)Person*
	ps1->_No = 10;

	pp = &pobj;//Person =Person
	Student* ps2 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题
	ps2->_No = 10;
}

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. The relationship between the subclass members and the parent class members is called hiding . If you have to access the members of the parent class, you can add an access qualifier to display the access

3. The function only needs to have the same function name to form a hidden function, and the parameters are irrelevant.

4. It is best not to define members with the same name

class Person
{
public:

protected:
	string _name="牡丹";
	int _num=18;
};

class Student :public Person
{
public:
	void Print()
	{
		cout << "姓名:" << _name << endl;
		cout << "学号:" << _num << endl;
		cout << "学号:" << Person::_num << endl;
	}
protected:
	int _num = 520;
};

int main(void)
{
	Student s1;
	s1.Print();
	return 0;
}

operation result:

class Person
{
public:
	void Print(int a)
	{
		cout << "姓名:" << _name << endl;
		cout << "学号:" << _num << endl;
	}
protected:
	string _name="牡丹";
	int _num=18;
};

class Student :public Person
{
public:
	void Print()
	{
		Person::Print(1);
		cout << "姓名:" << _name << endl;
		cout << "学号:" << _num << endl;
		cout << "学号:" << Person::_num << endl;
	}
protected:
	int _num = 520;
};

int main(void)
{
	Student s1;
	s1.Print();
	return 0;
}

What constitutes here is the hiding of the function rather than overloading, because it is not in the same scope

4. Default member functions of derived classes

6 default member functions, the default means that we do not write, the compiler will change us to automatically generate one, then in the derived class, these

How are member functions generated?

1. The constructor of the derived class must call the constructor of the base class to initialize the part of the base class. If the base class does not have a default constructor, it must be called explicitly in the initialization list phase of the derived class constructor.

2. The copy construction of the derived class must call the copy construction of the base class to complete the initialization of the base class.

3. The derived class operator=must call the base class operator=to complete the copy of the base class.

4. The destructor of the derived class will automatically call the destructor of the base class to clean up the members of the base class after being called . Because this ensures that derived classes

The order in which the object first cleans up derived class members and then cleans up base class members.

5. Derived class object initialization calls the base class construction first and then calls the derived class construction.

6. The derived class object destructor cleanup first calls the derived class destructor and then adjusts the base class destructor.

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 num)
		: Person(name)
		, _num(num)
	{
		cout << "Student()" << endl;
	}

	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; //学号
};
void Test()
{
	Student s1("jack", 18);
	Student s2(s1);
	Student s3("rose", 17);
	s1 = s3;
}

int main(void)
{
	Test();
	return 0;
}

This code:

实例化对象s1的时候会先去调用Student的构造函数,然后再Student的构造函数当中显示的调用了父类的构造函数。
实例化对象s2的时候先调用Student的拷贝构造,在拷贝构造的初始化列表当中显示的调用父类的拷贝构造
实例化s3的时候和s1一样
s1赋值给s3的时候先去调用子类的operator=,但是在子类当中会调用父类的operator=

Inheritance and Friends

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

Display is a friend of the base class Person. If Student also inherits the friendship relationship in Person, then the s._stuNum here is accessible, but the result is not accessible, so the friendship relationship cannot be inherited

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

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 ; // 研究科目
};
void TestPerson()
{
 Student s1 ;
 Student s2 ;
 Student s3 ;
 Graduate s4 ;
 cout <<" 人数 :"<< Person ::_count << endl;
 Student ::_count = 0;
 cout <<" 人数 :"<< Person ::_count << endl;
}

Complex Diamond Inheritance and Diamond Virtual Inheritance

Single inheritance: When a subclass has only one direct parent class, the inheritance relationship is called single inheritance

Multiple inheritance: When a subclass has two or more direct parent classes, the inheritance relationship is called multiple inheritance

Diamond inheritance: Diamond inheritance is a special case of multiple inheritance.

The problem of diamond inheritance: From the following object member model construction, it can be seen that diamond inheritance has data redundancy and ambiguity problems. 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; // 主修课程
};

void Test()
{
	// 这样会有二义性无法明确知道访问的是哪一个
	Assistant a;
	a._name = "peter";

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

Virtual inheritance can solve the ambiguity and data redundancy problems of diamond inheritance.


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

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

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

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

void Test()
{
	// 这样会有二义性无法明确知道访问的是哪一个
	Assistant a;
	a._name = "peter";

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

int main(void)
{
	Test();
	return 0;
}

In this way, they all point _nameto the same thing _name.

7. The principle of virtual inheritance to solve data redundancy and ambiguity

It can be seen that the members of virtual inheritance are all placed in the public area, but there are two more addresses here, which look like two pointers

It can be seen that there is a 14sum here 0c, the hexadecimal of 14 is 20, and c is 12, which just records the distance from the current class to the public area.

Guess you like

Origin blog.csdn.net/AkieMo/article/details/131625705