c++学习笔记——类的继承

c++类的继承

1.1继承与派生

派生类是基类的具体化,而基类是派生类的抽象
一个派生类只从一个基类中派生,称为单继承
一个派生类有多个基类,称为多重继承

1.2派生类的声明方式

固定格式:

class 派生类名:[继承方式] 基类名
{
派生类新增的成员
}

1.3派生类成员的访问方式

构造一个派生类包括以下三个工作:
1.从基类中接受成员。

派生类不加选择的继承基类的全部成员(不包括构造函数与析构函数)。
表面上父类中的私有成员无法访问,是因为父类中的私有成员被编译器隐藏,因此只是访问不到,但确实被继承

2.调整从基类的成员

我们无法对接受什么成员做选择,但可以对这些成员的属性做某些调整,即公用继承,私有继承,保护继承。
可以在派生类中声明一个与基类成员同名的成员,或者同名的成员函数,之后会详细讲解

3.在声明派生类时增加的成员

这一部分体现了派生类对基类成员的功能的拓展与个性。
同时,在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数,因为两者不能通过继承得到。

1.4公用继承,私有继承,保护继承

1)共用继承

各成员属性不变,保持原有的继承属性

举例,请阅读下面的程序:

#include<iostream>
using namespace std;
class Student
{
public:
    void get_value()//输入基类数据的成员函数
    {
        cin >> num >> name >> sex;
    }
    void display()
    {
        cout << "num:" << num << endl;
        cout << "nmae:" << 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 << "num:" << num << endl;
      //cout << "nmae:" << name << endl;
      //cout << "sex:" << sex << endl;
      //由于上述数据在基类中私有,所以派生类中的输出函数无法直接调用,
      //但是我们可以直接在派生调用基类公有的输出函数。
        display();
        cout << "age:" << age << endl;
        cout << "addr:" << addr << endl;
    }
private:
    int age;
    string addr;
};
int main()
{
    Student1 stu1;
    stu1.get_value();
    stu1.get_value_1();
    stu1.display_1();
    return 0;
}

2)私有继承

继承的各成员属性全变成私有

举例,还是上面的例子,把公有继承换成私有继承,观察与上一个例子的差异

#include<iostream>
using namespace std;
class Student
{
public:
    void get_value()//输入基类数据的成员函数
    {
        cin >> num >> name >> sex;
    }
    void display()
    {
        cout << "num:" << num << endl;
        cout << "nmae:" << 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 << "addr:" << addr << endl;
    }
private:
    int age;
    string addr;
};
int main()
{
    Student1 stu1;
    //stu1.get_value();  //无法在类外调用派生类中的私有函数
    stu1.get_value_1();
    stu1.display_1();
    return 0;
}

3)受保护的继承

继承的各成员属性全变成被保护类型
ps:保护成员的含义:不能被外界引用,但可以被派生类的成员使用,某种程度上与私有类似。

保护成员与私有成员的差异

从类的角度看,保护成员等价于私有成员。但有一点与私有成员不同,基类中的保护成员可以被派生类的成员函数引用。
基类中的私有成员被派生类继承后,变成了不可访问的成员,派生类中的一切成员均无法访问他们。如果需要在派生类中引用积累的某些成员,应当将基类的这些成员声明为protected,而不是private.

1.5派生类的构造函数与析构函数

为什么需要构造函数?
如果我们需要对类中的数据成员初始化,应该自己定义构造函数

派生类构造函数的一般形式
派生类构造函数名(总参表):基类构造函数名(参数表
{
派生类中新增数据成员的初始化语句;
}

派生类构造函数的各种形式

  • 一般形式
Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)
	{
		age = a;
		addr = ad;
	}
  • 跳过总参表,使用常量或全局变量
Student1(string nam, char s, int a, string ad) :Student(10010, nam, s)
	{
		age = a;
		addr = ad;
	}
  • 初始化表形式

这种方法利用之前学习过的初始化表
类似于 Box::Box(int h ,int,w ,int len ):height(h) ,width(w) ,length(len){}
这样使函数体为空,更显得简单与方便

Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)age(a),addr(ad){}

1.5.1 简单的派生类的构造函数

#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
	Student(int n, string nam, char s)
	{
		num = n;
		name = nam;
		sex = s;
	}
	void display()
	{
		cout << "num:" << num << endl;
		cout << "name:" << name << endl;
		cout<<"sex:"<< sex << endl;
	}
	~Student(){}
protected:
	int num;
	string name;
	char sex;

};
class Student1 :public Student
{
public:
   //构造函数
   //对于Student(n,nam,s)来说,括号中的参数列表只有参数名而不包括参数类型,
   //因为这里不是定义基类构造函数,而是调用基类构造函数,因此这些参数是实参而不是形参。
	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 << "addr:" << addr << endl;
	}

	~Student1(){}
protected:
	int age;
	string addr;

};

int main()
{
	Student1 stu1(001, "甲", 'm', 20, "china");
	Student1 stu2(002, "乙", 'f', 30, "france");
	stu1.show();
	stu2.show();
	return 0;

}

补充: 派生类的构造函数也可以在类外定义


类内只写函数声明:
Student1(int n, string nam, char s, int a, string ad)
类外写函数定义
Student1::Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)
{
age = a;
addr = ad;
}

1.5.2 有子对象的派生类的构造函数

应用背景:
当类中的数据成员需要包含类对象时。

#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
	Student(int n, string nam, char s)
	{
		num = n;
		name = nam;
		sex = s;
	}
	void display()
	{
		cout << "num:" << num << endl;
		cout << "name:" << name << endl;
		cout<<"sex:"<< sex << endl;
	}
	~Student(){}
protected:
	int num;
	string name;
	char sex;

};
class Student1 :public Student
{
public:
//构造函数
	Student1(int n, string nam, char s, int a, string ad,int n1,string nam1,char s1) :Student(n, nam, s),monitor(n1,nam1,s1)
	{
		age = a;
		addr = ad;
	}
	void show()
	{
		cout << "num:" << num << endl;
		cout << "name:" << name << endl;
		cout << "sex:" << sex << endl;
		cout << "age:" << age << endl;
		cout << "addr:" << addr << endl;
	}
	void monitor_show()
	{
		cout << "monitor is:>" << endl;
		display();//调用基类中的输出函数
	}
	~Student1(){}
protected:
	Student monitor;//子对象
	int age;
	string addr;

};

int main()

{
	Student1 stu1(001, "甲", 'm', 20, "china",002,"乙",'m');
	stu1.show();
	stu1.monitor_show();
	return 0;

}

1.5.3 多层派生的构造函数

书写注意事项
构造函数,只须写出上一层派生类(即他的直接基类)的构造函数

初始化的顺序
先初始化基类的数据成员,再初始化Student1,最后Student2

#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
	Student(int n, string nam, char s)
	{
		num = n;
		name = nam;
		sex = s;
	}
	void display()
	{
		cout << "num:" << num << endl;
		cout << "name:" << name << endl;
		cout<<"sex:"<< sex << endl;
	}
	~Student(){}
protected:
	int num;
	string name;
	char sex;

};
class Student1 :public Student
{
public:
	Student1(int n, string nam, char s, int a, string ad,int n1,string nam1,char s1) :Student(n, nam, s),monitor(n1,nam1,s1)
	{
		age = a;
		addr = ad;
	}
	void show()
	{
		cout << "num:" << num << endl;
		cout << "name:" << name << endl;
		cout << "sex:" << sex << endl;
		cout << "age:" << age << endl;
		cout << "addr:" << addr << endl;
	}
	void monitor_show()
	{
		cout << "monitor is:>" << endl;
		display();
	}
	~Student1(){}
protected:
	Student monitor;//子对象
	int age;
	string addr;

};
class Student2 :public Student1
{
public:
	Student2(int n, string nam, char s, int a, string ad,int n1, string nam1, char s1,int k) :Student1(n, nam, a, s, ad,n1,nam1,s1)
	{
		score = k;
	}
	void show_all()
	{
		show();
		cout << "score:" << score << endl;
	}
protected:
	int score;

};
int main()

{
	Student1 stu1(001, "甲", 'm', 20, "china",003,"丁",'m');
	// stu2(002, "乙", 'f', 30, "france");
	//Student monitor(004, "丙", 'm');
	stu1.show();
	cout << endl;
	stu1.monitor_show();
	cout << endl;
	//monitor.display();
	//stu2.show();
	Student2 stu2(001, "甲", 'm', 20, "china", 003, "丁", 'm', 200);
	stu2.show_all();
	cout << endl;
	stu2.monitor_show();
	return 0;

}

1.5.4 派生类的析构函数

继承中构造与析构的顺序
先构造父类,再子类
先析构子类,再父类

1.6继承同名成员处理方法

问题:当子类与父类出现同名的成员,如何通过子类对象,访问到父类中的同名的数据呢?

访问子类同名成员 :直接访问即可
访问父类同名成员:需要加作用域

1.同名成员数据

#include<iostream>
using namespace std;

class Base
{
public:
    Base()
    {
        m_A = 100;
    }
    int m_A;
};
class Son:public Base
{
public:
    Son()
    {
        m_A = 200;
    }
    int m_A;
};
int main()
{
    Son s;
    cout << " Son m_A:" << s.m_A << endl;
    cout << " Base m_A:" << s.Base::m_A << endl;
}

2.同名成员函数

如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数
如果想访问到父类被隐藏的同名成员函数,需要加作用域

#include<iostream>
using namespace std;

class Base
{
public:
    Base()
    {
        m_A = 100;
    }
    
    void func()
    {
        cout << "Base-func函数调用" << endl;
    }
    
    void func(int a)
    {
        cout << a;
    }
    int m_A;
};
class Son:public Base
{
public:
    Son()
    {
        m_A = 200;
    }
    void func()
    {
        cout << "Son-func函数调用" << endl;
    }
    int m_A;
};
int main()
{
    Son s;
    s.func();
    s.Base::func();
    s.Base::func(100);
}

虚基类

c++提供虚基类的方法,使得继承间接共同基类时只保留一份成员
注:为保证虚基类在派生类中只继承了一次,应当在该基类的所有直接派生类声明为虚基类,否则任然会出现对基类的多次继承

举例:

#include<iostream>
using namespace std;
#include<string>

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 sc):Person(nam,s,a),score(sc){}
protected:
	float score;
};
//总类
class Graduate :public Teacher, public Student
{
public:
	Graduate(string nam,char s,int a,string t,float sc,float w):Person(nam,s,a),Teacher(nam,s,a,t),Student(nam,s,a,sc),
    wage(w){}

	void show()
	{
		cout << name << endl;
		cout << age << endl;
		cout << title << endl;

		cout << sex << endl;
		cout << score << endl;

		cout << wage << endl;
	}
private:
	float wage;
};

void test()
{
	Graduate g("wang",'f',20, "student",89.5, 2400);
	g.show();

}
int main()
{
	test();

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ornamrr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值