C++学习笔记——04 类的继承


🌿前言:本系列笔记是主要是对于谭浩强的c++程序设计的学习笔记再加上一些我自己的理解。如果有误欢迎大家指出。

建议是有基础的同学快速入门,或者复习用

一、继承与派生

  • 在C++中可重用性是通过继承来实现的。

  • 继承——一个新类从已有的类那里获得其已有的特性。已有的类,称为基类或父类;新建的类,称为派生类或子类。基类和派生类是相对而言的。

  • 继承层次结构:一代代派生下去

  • 单继承:一个派生类只从一个基类中派生,即该派生类只有一个基类

  • 多重继承:一个派生类有两个或多个基类

二、派生类的声明方式

class Student1:public Student
{
    public:
    void display_1();
    {
        
    }
    private:
    int age;
    string addr;
};

公用继承

声明派生类的一般形式:

class 派生类名:[继承方式] 基类名

{

派生类新增成员

};

继承方式:公用继承public,保护继承protected,私有继承private(不写此项默认私有)

三、派生类的构成

  • 派生类包括:从基类继承来的成员,以及在声明派生类时增加的部分,这两个部分都包含了数据成员和成员函数。

  • 构造派生的三个工作:

    从基类不可选择地接收成员。(不接收构造和析构函数)

    调整从基类接收的成员(如通过改变继承方式来改变基类成员在派生类中的访问属性,或同名覆盖)

    在声明派生类时增加的成员(一般还应该自己定义派生类的构造和析构函数)

四、派生类的访问属性

公用继承(public)

基类的公有成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有。

只能通过基类的公用成员函数来引用基类的私有成员

#include<iostream>
using namespace std;
class Student
{
	public:
		void get_value()
		{
			cin>>num>>name>>sex;
		}
		void display()
		{
			cout<<"num:"<<num<<endl;
			cout<<"name:"<<name<<endl;
			cout<<"sex:"<<sex<<endl;	
		}
	private:
		int num;
		string name;
		char sex;
};
class Student1:public Student
{
	public:
		void get_value_1()
		{
			cin>>age>>addr;
		}
		void display_1()
		{
			cout<<"age:"<<age<<endl;
			cout<<"address:"<<addr<<endl;
		}
	private:
		int age;
		string addr;
};
int main()
{
	Student1 stud;
	stud.get_value();
	stud.get_value_1();
	stud.display();
	stud.display_1();
	return 0;
}

私有继承(private)

基类的公有成员和保护成员在派生类中成为私有成员,其私有成员仍为基类私有。

#include<iostream>
using namespace std;
class Student
{
	public:
		void get_value()
		{
			cin>>num>>name>>sex;
		}
		void display()
		{
			cout<<"num:"<<num<<endl;
			cout<<"name:"<<name<<endl;
			cout<<"sex:"<<sex<<endl;	
		}
	private:
		int num;
		string name;
		char sex;
};
class Student1:private Student
{
	public:
		void get_value_1()
		{
			get_value();
			cin>>age>>addr;
		}
		void display_1()
		{
			display();
			cout<<"age:"<<age<<endl;
			cout<<"address:"<<addr<<endl;
		}
	private:
		int age;
		string addr;
};
int main()
{
	Student1 stud1;
	stud1.get_value_1();
	stud1.display_1();
	return 0;
}

保护继承(protected)

基类的公有成员和保护成员在派生类中成为保护成员,其私有成员仍为基类私有。

保护成员可以被派生类的成员函数引用

#include<iostream>
#include<string>
using namespace std;
class Student
{
	protected:
		int num;
		string name;
		char sex;
};
class Student1:protected Student
{
	public:
		void get_value_1();
		void display_1();
	private:
		int age;
		string addr;
};
void Student1::get_value_1()
{
	cin>>num>>name>>sex;
	cin>>age>>addr;
}
void Student1::display_1()
{
	cout<<"num:"<<num<<endl;
	cout<<"name:"<<name<<endl;
	cout<<"sex:"<<sex<<endl;
	cout<<"age:"<<age<<endl;
	cout<<"address:"<<addr<<endl;
}
int main()
{
	Student1 stud1;
	stud1.get_value_1();
	stud1.display_1();
	return 0;
}

多级派生时的访问属性:逐个分析即可

五、派生类的构造函数和析构函数

希望在执行派生类的构造函数时,使派生类和基类的数据成员都被初始化,可以在执行派生类的构造函数时,调用基类的构造函数

1.简单的派生类的构造函数
#include<iostream>
#include<string>
using namespace std;
class Student
{
	public:
		Student(int n,string nam,char s)
		{
			num=n;
			name=nam;
			sex=s;
		}
		~Student(){}
	protected:
		int num;
		string name;
		char sex;
};
class Student1:public Student
{
	public:
		Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)
		{
			age=a;
			addr=ad;
		}
		void show()
		{
			cout<<"num:"<<num<<endl;
			cout<<"name:"<<name<<endl;
			cout<<"sex:"<<sex<<endl;
			cout<<"age:"<<age<<endl;
			cout<<"address:"<<addr<<endl;
		}
		~Student1(){}
	private:
		int age;
		string addr;
};
int main()
{
	Student1 stud1(10010,"Wangli",'f',19,"115Beijing Road,Shanghai");
	Student1 stud2(10011,"Zhangfan",'m',21,"213Shanghai Road,Beijing");
	stud1.show();
	stud2.show();
	return 0;
}
  • 派生类构造函数的一般形式

    派生类构造函数名(总参数表):基类构造函数名(参数表)

    {派生类新增成员初始化语句}

    派生类的参数表含参数类型和参数名,基类的只含参数名(因为这里只是调用)

  • 在类中对派生类的构造函数声明时不包括基类构造函数部分,定义时才列出

  • 构造顺序:先派生类构造函数调用基类的,再执行自己本身

    析构顺序:先析构派生类再基类

2.有子对象的派生类的构造函数
#include<iostream>
#include<string>
using namespace std;
class Student
{
	public:
		Student(int n,string nam)
		{
			num=n;
			name=nam;
		}
		void display()
		{
			cout<<"num:"<<num<<endl<<"name:"<<name<<endl;
		}
	protected:
		int num;
		string name;
};
class Student1:public Student
{
	public:
		Student1(int n,string nam,int n1,string nam1,int a,string ad):Student(n,nam),monitor(n1,nam1)
		{
			age=a;
			addr=ad;
		}
		void show()
		{
			cout<<"This student is:"<<endl;
			display();
			cout<<"age:"<<age<<endl;
			cout<<"address:"<<addr<<endl<<endl;
		}
		void show_monitor()
		{
			cout<<endl<<"class monitor is:"<<endl;
			monitor.display();
		}
		private:
			Student monitor;
			int age;
			string addr;
};
int main()
{
	Student1 stud1(10010,"Wang_li",10001,"Li_jun",19,"115 beijing road");
	stud1.show();
	stud1.show_monitor();
	return 0;
}
  • 有子对象的派生类构造函数的一般形式

    派生类构造函数名(总参数表):基类构造函数名(参数表),子对象名(参数表)

    {派生类新增成员初始化语句}

    基类构造函数和子对象的次序可以是任意的。

  • 构造顺序:先派生类构造函数调用基类的,再子对象的,再执行自己本身

    析构顺序:先析构派生类再子对象的再基类

3.多层派生时的构造函数
#include<iostream>
#include<string>
using namespace std;
class Student
{
	public:
		Student(int n,string nam)
		{
			num=n;
			name=nam;
		}
		void display()
		{
			cout<<"num:"<<num<<endl<<"name:"<<name<<endl;
		}
	protected:
		int num;
		string name;
};
class Student1:public Student
{
	public:
		Student1(int n,string nam,int a):Student(n,nam){age=a;}
		void show()
		{
			display();
			cout<<"age:"<<age<<endl;
		}
		private:
            int age;
};
class Student2:public Student1
{
	public:
		Student2(int n,string nam,int a,int s):Student1(n,nam,a){score=s;}
		void show_all()
		{
			show();
			cout<<"score:"<<score<<endl;
		}
	private:
		int score;
};
int main()
{
	Student2 stud(10010,"Li",17,89);
	stud.show_all();
	return 0;
}

定义时,无需列出每一层的构造函数,列出上一层的即可

4.派生类构造函数的特殊形式

如果基类和子对象类型的声明中都没有定义带参数的构造函数,而且也不需对派生类自己的数据成员初始化,则不必显式的定义派生类构造函数。

5.派生类的析构函数

同样需要通过派生类的析构函数来调用基类的去清理

六、多重继承

1.声明多重继承的方法

class D:public A,private B,protected C

{类D新增的成员的初始化语句}

2.多重继承派生类的构造函数

与单继承的形式基本相同,只是在初始化时包含多个基类构造函数

#include<iostream>
#include<string.h>
using namespace std;
class Teacher
{
	public:
		Teacher(string nam,int a,string t)
		{
			name=nam;
			age=a;
			title=t;
		}
		void display()
		{
			cout<<"name:"<<name<<endl;
			cout<<"age:"<<age<<endl;
			cout<<"title:"<<title<<endl;
		}
	protected:
		string name;
		int age;
		string title;
};
class Student
{
	public:
		Student(string nam,char s,float sco)
		{
			name1=nam;
			sex=s;
			score=sco;
		}
		void display()
		{
			cout<<"name:"<<name1<<endl;
			cout<<"sex:"<<sex<<endl;
			cout<<"score:"<<score<<endl;
		}
	protected:
		string name1;
		char sex;
		float score;
};
class Graduate:public Teacher,public Student
{
	public:
		Graduate(string nam,int a,char s,string t,float sco,float w):Teacher(nam,a,t),Student(nam,s,sco),wage(w){}
		void show()
		{
			cout<<"name:"<<Teacher::name<<endl;
			cout<<"age:"<<age<<endl;
			cout<<"sex:"<<sex<<endl;
			cout<<"score:"<<score<<endl;
			cout<<"title:"<<title<<endl;
			cout<<"wages:"<<wage<<endl;
		};
	private:
		float wage;
};
int main()
{
	Graduate grad1("Wang_li",24,'f',"assistant",89.5,2400);
	grad1.show();
	return 0;
}
3.多重继承引起的二义性问题

1.两个基类有同名成员:用基类名来限定,派生类访问基类成员时可以不写对象名直接写基类名

2.两个基类和派生类都有同名成员:发生同名覆盖

3.如果两个基类的基类是同一个:用它们的基类的直接派生类名限定,即两个基类的类名

4.虚基类

虚基类:在继承间接共同基类时减少冗余,只保留一份共同成员

虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的

class 派生类名:virtual 继承方式 基类名

要在所有直接派生类中都声明,不然有漏网之鱼

在最后的派生类中不仅要对其直接基类初始化,还要负责对虚基类初始化

#include<iostream>
#include<string.h>
using namespace std;
class Person
{
	public:
		Person(string nam,char s,int a)
		{
			name=nam;sex=s;age=a;
		}
	protected:
		string name;
		char sex;
		int age;
};
class Teacher:virtual public Person
{
	public:
		Teacher(string nam,char s,int a,string t):Person(nam,s,a)
		{title=t;}
	protected:
		string title;
};
class Student:virtual public Person
{
	public:
		Student(string nam,char s,int a,float sco):Person(nam,s,a),score(sco){}
    protected:
		float score;
};
class Graduate:public Teacher,public Student
{
	public:
		Graduate(string nam,char s,int a,string t,float sco,float w):Person(nam,s,a),Teacher(nam,s,a,t),Student(nam,s,a,sco),wage(w){}
		void show()
		{
			cout<<"name:"<<Teacher::name<<endl;
			cout<<"age:"<<age<<endl;
			cout<<"sex:"<<sex<<endl;
			cout<<"score:"<<score<<endl;
			cout<<"title:"<<title<<endl;
			cout<<"wages:"<<wage<<endl;
		};
	private:
		float wage;
};
int main()
{
	Graduate grad1("Wang_li",'f',24,"assistant",89.5,1200);
	grad1.show();
	return 0;
}

七、基类与派生类的转换

1.派生类对象可以对基类对象赋值(只对数据成员)

2.派生类对象可以代替基类对象向基类对象的引用进行赋值或初始化

3.如果函数的参数是基类对象或基类对象的引用,相应实参可以用子对象

4.指向基类的指针变量也可以指向派生类(但只能访问派生类中的基类成员,新增的不可以)

#include<iostream>
#include<string>
using namespace std;
class Student
{
	public:
		Student(int,string,float);
		void display();
	private:
		int num;
		string name;
		float score;
};
Student::Student(int n,string nam,float s)
{
	num=n;
	name=nam;
	score=s;
}
void Student::display()
{
	cout<<endl<<"num:"<<num<<endl;
	cout<<"name:"<<name<<endl;
	cout<<"score:"<<score<<endl;
}
class Graduate:public Student
{
	public:
		Graduate(int,string,float,float);
		void display();
	private:
		float wage;
};
Graduate::Graduate(int n,string nam,float s,float w):Student(n,nam,s),wage(w){}
void Graduate::display()
{
	Student::display();
	cout<<"wage="<<wage<<endl;
}
int main()
{
	Student stud1(10010,"Li",87.5);
	Graduate grad1(2001,"wang",98.5,1000);
	Student *pt=&stud1;
	pt->display();
	pt=&grad1;
	pt->display();
	return 0;
}

八、继承和组合

在一个类中以另一个类的对象作为数据成员,称为类的组合

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值