Skip to content

Wiki

Inheritance

About 11 min read

1.Inheritance

Inheritance is one of the three major features of object-oriented programming.

Some classes have special relationships with each other, as shown in the following figure:

1544861202252

We found that when defining these classes, members at the lower level not only possess the commonalities of the upper level but also have their own characteristics.

At this point, we can consider using inheritance techniques to reduce duplicate code.

1.1.Basic syntax of inheritance

For example, we see that many websites have a common header, a common footer, and even a common left-side list, with only the central content differing.

Next, we will implement the content on the webpage using both the ordinary approach and the inheritance approach, and examine the significance and benefits of inheritance.

Common implementation:

//Java页面
class Java 
{
public:
	void header()
	{
		cout << "首页、公开课、登录、注册...(公共头部)" << endl;
	}
	void footer()
	{
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
		cout << "Java,Python,C++...(公共分类列表)" << endl;
	}
	void content()
	{
		cout << "JAVA学科视频" << endl;
	}
};
//Python页面
class Python
{
public:
	void header()
	{
		cout << "首页、公开课、登录、注册...(公共头部)" << endl;
	}
	void footer()
	{
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
		cout << "Java,Python,C++...(公共分类列表)" << endl;
	}
	void content()
	{
		cout << "Python学科视频" << endl;
	}
};
//C++页面
class CPP 
{
public:
	void header()
	{
		cout << "首页、公开课、登录、注册...(公共头部)" << endl;
	}
	void footer()
	{
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
		cout << "Java,Python,C++...(公共分类列表)" << endl;
	}
	void content()
	{
		cout << "C++学科视频" << endl;
	}
};

void test01()
{
	//Java页面
	cout << "Java下载视频页面如下: " << endl;
	Java ja;
	ja.header();
	ja.footer();
	ja.left();
	ja.content();
	cout << "--------------------" << endl;

	//Python页面
	cout << "Python下载视频页面如下: " << endl;
	Python py;
	py.header();
	py.footer();
	py.left();
	py.content();
	cout << "--------------------" << endl;

	//C++页面
	cout << "C++下载视频页面如下: " << endl;
	CPP cp;
	cp.header();
	cp.footer();
	cp.left();
	cp.content();

}

int main() {

	test01();


	return 0;
}

Operation result:

Java下载视频页面如下:
首页、公开课、登录、注册...(公共头部)
帮助中心、交流合作、站内地图...(公共底部)
Java,Python,C++...(公共分类列表)
JAVA学科视频
--------------------
Python下载视频页面如下:
首页、公开课、登录、注册...(公共头部)
帮助中心、交流合作、站内地图...(公共底部)
Java,Python,C++...(公共分类列表)
Python学科视频
--------------------
C++下载视频页面如下:
首页、公开课、登录、注册...(公共头部)
帮助中心、交流合作、站内地图...(公共底部)
Java,Python,C++...(公共分类列表)
C++学科视频

Inheritance implementation:

//公共页面
class BasePage
{
public:
	void header()
	{
		cout << "首页、公开课、登录、注册...(公共头部)" << endl;
	}

	void footer()
	{
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
		cout << "Java,Python,C++...(公共分类列表)" << endl;
	}

};

//Java页面
class Java : public BasePage
{
public:
	void content()
	{
		cout << "JAVA学科视频" << endl;
	}
};
//Python页面
class Python : public BasePage
{
public:
	void content()
	{
		cout << "Python学科视频" << endl;
	}
};
//C++页面
class CPP : public BasePage
{
public:
	void content()
	{
		cout << "C++学科视频" << endl;
	}
};

void test01()
{
	//Java页面
	cout << "Java下载视频页面如下: " << endl;
	Java ja;
	ja.header();
	ja.footer();
	ja.left();
	ja.content();
	cout << "--------------------" << endl;

	//Python页面
	cout << "Python下载视频页面如下: " << endl;
	Python py;
	py.header();
	py.footer();
	py.left();
	py.content();
	cout << "--------------------" << endl;

	//C++页面
	cout << "C++下载视频页面如下: " << endl;
	CPP cp;
	cp.header();
	cp.footer();
	cp.left();
	cp.content();

}

int main() {

	test01();


	return 0;
}

Operation result:

Java下载视频页面如下:
首页、公开课、登录、注册...(公共头部)
帮助中心、交流合作、站内地图...(公共底部)
Java,Python,C++...(公共分类列表)
JAVA学科视频
--------------------
Python下载视频页面如下:
首页、公开课、登录、注册...(公共头部)
帮助中心、交流合作、站内地图...(公共底部)
Java,Python,C++...(公共分类列表)
Python学科视频
--------------------
C++下载视频页面如下:
首页、公开课、登录、注册...(公共头部)
帮助中心、交流合作、站内地图...(公共底部)
Java,Python,C++...(公共分类列表)
C++学科视频

Summary:

Benefits of inheritance: ==can reduce duplicate code==

class A : public B;

Class A is called a subclass or derived class.

Class B is called the parent class or base class.

Members in a derived class, including two major parts:

One category is inherited from the base class, and the other category consists of members added by itself.

The members inherited from the base class express their commonality, while the newly added members express their individuality.

1.2.Inheritance method

Inheritance syntax:class 子类 : 继承方式 父类

There are three inheritance modes in total:

  • Public inheritance
  • Protected inheritance
  • Private inheritance

img

Example:

class Base1
{
public: 
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};

//公共继承
class Son1 :public Base1
{
public:
	void func()
	{
		m_A; //可访问 public权限
		m_B; //可访问 protected权限
		//m_C; //不可访问
	}
};

void myClass()
{
	Son1 s1;
	s1.m_A; //其他类只能访问到公共权限
}

//保护继承
class Base2
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};
class Son2:protected Base2
{
public:
	void func()
	{
		m_A; //可访问 protected权限
		m_B; //可访问 protected权限
		//m_C; //不可访问
	}
};
void myClass2()
{
	Son2 s;
	//s.m_A; //不可访问
}

//私有继承
class Base3
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};
class Son3:private Base3
{
public:
	void func()
	{
		m_A; //可访问 private权限
		m_B; //可访问 private权限
		//m_C; //不可访问
	}
};
class GrandSon3 :public Son3
{
public:
	void func()
	{
		//Son3是私有继承,所以继承Son3的属性在GrandSon3中都无法访问到
		//m_A;
		//m_B;
		//m_C;
	}
};

Run result: This code block does not contain the main function; it is a syntax, interface, or multi-file example and cannot be run independently, so there is no terminal output.

1.3.Object model in inheritance

**Question:** Among the members inherited from the parent class, which ones belong to the subclass object?

Example:

class Base
{
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C; //私有成员只是被隐藏了,但是还是会继承下去
};

//公共继承
class Son :public Base
{
public:
	int m_D;
};

void test01()
{
	cout << "sizeof Son = " << sizeof(Son) << endl;
}

int main() {

	test01();


	return 0;
}

Run result (type size or type name may vary depending on compiler and platform):

sizeof Son = 16

View using a tool:

1545881904150

After opening the tool window, locate the drive letter of the current CPP file

Then enter: cl /d1 reportSingleClassLayoutClass name to view File name to which it belongs

The effect is shown in the following figure:

1545882158050

Conclusion: Private members in the parent class are also inherited by the subclass; they are merely hidden by the compiler and cannot be accessed.

1.4.Order of Construction and Destruction in Inheritance

After a subclass inherits from a parent class, when a subclass object is created, the parent class's constructor is also called.

Question: In what order are the constructors and destructors of a parent class and a child class called?

Example:

class Base 
{
public:
	Base()
	{
		cout << "Base构造函数!" << endl;
	}
	~Base()
	{
		cout << "Base析构函数!" << endl;
	}
};

class Son : public Base
{
public:
	Son()
	{
		cout << "Son构造函数!" << endl;
	}
	~Son()
	{
		cout << "Son析构函数!" << endl;
	}

};

void test01()
{
	//继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
	Son s;
}

int main() {

	test01();


	return 0;
}

Operation result:

Base构造函数!
Son构造函数!
Son析构函数!
Base析构函数!

Summary: In inheritance, the parent class constructor is called first, then the child class constructor; the destruction order is the reverse of construction.

1.5.Handling of Inherited Members with the Same Name

Question: When a subclass and a parent class have members with the same name, how can the identically named data in the subclass or the parent class be accessed through a subclass object?

  • Accessing a member with the same name in a subclass Direct access is sufficient
  • Accessing a member with the same name in the parent class Scope resolution is required

Example:

class Base {
public:
	Base()
	{
		m_A = 100;
	}

	void func()
	{
		cout << "Base - func()调用" << endl;
	}

	void func(int a)
	{
		cout << "Base - func(int a)调用" << endl;
	}

public:
	int m_A;
};

class Son : public Base {
public:
	Son()
	{
		m_A = 200;
	}

	//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
	//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
	void func()
	{
		cout << "Son - func()调用" << endl;
	}
public:
	int m_A;
};

void test01()
{
	Son s;

	cout << "Son下的m_A = " << s.m_A << endl;
	cout << "Base下的m_A = " << s.Base::m_A << endl;

	s.func();
	s.Base::func();
	s.Base::func(10);

}
int main() {

	test01();

	return EXIT_SUCCESS;
}

Operation result:

Son下的m_A = 200
Base下的m_A = 100
Son - func()调用
Base - func()调用
Base - func(int a)调用

Summary:

  1. A subclass object can directly access the member with the same name in the subclass.
  2. A subclass object with scope resolution can access the member with the same name in the parent class.
  3. When a subclass and parent class have member functions with the same name, the subclass hides the member function with the same name in the parent class, and scope resolution can access the function with the same name in the parent class.

1.6.Handling of inherited static members with the same name

Question: How are static members with the same name accessed on subclass objects in inheritance?

When static members and non-static members have the same name, the handling method is consistent.

  • Accessing a subclass member with the same name access it directly
  • Accessing a parent class member with the same name you need to add the scope

Example:

class Base {
public:
	static void func()
	{
		cout << "Base - static void func()" << endl;
	}
	static void func(int a)
	{
		cout << "Base - static void func(int a)" << endl;
	}

	static int m_A;
};

int Base::m_A = 100;

class Son : public Base {
public:
	static void func()
	{
		cout << "Son - static void func()" << endl;
	}
	static int m_A;
};

int Son::m_A = 200;

//同名成员属性
void test01()
{
	//通过对象访问
	cout << "通过对象访问: " << endl;
	Son s;
	cout << "Son  下 m_A = " << s.m_A << endl;
	cout << "Base 下 m_A = " << s.Base::m_A << endl;

	//通过类名访问
	cout << "通过类名访问: " << endl;
	cout << "Son  下 m_A = " << Son::m_A << endl;
	cout << "Base 下 m_A = " << Son::Base::m_A << endl;
}

//同名成员函数
void test02()
{
	//通过对象访问
	cout << "通过对象访问: " << endl;
	Son s;
	s.func();
	s.Base::func();

	cout << "通过类名访问: " << endl;
	Son::func();
	Son::Base::func();
	//出现同名,子类会隐藏掉父类中所有同名成员函数,需要加作作用域访问
	Son::Base::func(100);
}
int main() {

	//test01();
	test02();


	return 0;
}

Operation result:

通过对象访问:
Son - static void func()
Base - static void func()
通过类名访问:
Son - static void func()
Base - static void func()
Base - static void func(int a)

Summary: Static members with the same name are handled in the same way as non-static ones, except that there are two ways to access them (through an object and through the class name).

1.7.Multiple inheritance syntax

C++Allowsa class to inherit from multiple classes

Syntax: class 子类 :继承方式 父类1 , 继承方式 父类2...

Multiple inheritance may cause members with the same name to appear in parent classes, requiring scope qualification to distinguish them.

C++Multiple inheritance is not recommended in actual development.

Example:

class Base1 {
public:
	Base1()
	{
		m_A = 100;
	}
public:
	int m_A;
};

class Base2 {
public:
	Base2()
	{
		m_A = 200;  //开始是m_B 不会出问题,但是改为mA就会出现不明确
	}
public:
	int m_A;
};

//语法:class 子类:继承方式 父类1 ,继承方式 父类2 
class Son : public Base2, public Base1 
{
public:
	Son()
	{
		m_C = 300;
		m_D = 400;
	}
public:
	int m_C;
	int m_D;
};

//多继承容易产生成员同名的情况
//通过使用类名作用域可以区分调用哪一个基类的成员
void test01()
{
	Son s;
	cout << "sizeof Son = " << sizeof(s) << endl;
	cout << s.Base1::m_A << endl;
	cout << s.Base2::m_A << endl;
}

int main() {

	test01();


	return 0;
}

Run result (type size or type name may vary depending on compiler and platform):

sizeof Son = 16
100
200

Summary: In multiple inheritance, if a name conflict occurs among the parent classes, the subclass must use scope resolution when accessing it.

1.8.diamond inheritance

Diamond inheritance concept:

Two derived classes inherit from the same base class.

​ And there is a class that simultaneously inherits from two derived classes.

This kind of inheritance is called diamond inheritance, or diamond-shaped inheritance.

Typical diamond inheritance case:

IMG_256

Diamond inheritance problem:

  1. 羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时,就会产生二义性。
    
  2. The data that alpaca inherits from the animal is inherited twice; in fact, we should be clear that we only need one copy of this data.

Example:

class Animal
{
public:
	int m_Age;
};

//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类
class Sheep : virtual public Animal {};
class Tuo   : virtual public Animal {};
class SheepTuo : public Sheep, public Tuo {};

void test01()
{
	SheepTuo st;
	st.Sheep::m_Age = 100;
	st.Tuo::m_Age = 200;

	cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
	cout << "st.Tuo::m_Age = " <<  st.Tuo::m_Age << endl;
	cout << "st.m_Age = " << st.m_Age << endl;
}

int main() {

	test01();


	return 0;
}

Operation result:

st.Sheep::m_Age = 200
st.Tuo::m_Age = 200
st.m_Age = 200

Summary:

  • The main problem caused by diamond inheritance is that a subclass inherits two copies of the same data, leading to resource waste and meaninglessness.
  • Using virtual inheritance can solve the diamond inheritance problem.