一.继承与派生
1.类的继承与派生
继承:对类实现分层
被继承的类:基类 新产生的类:派生类(子类)
Ex. 基类:学校,由学校派生出两个类:学生,教职工
再由学生派生出:本科生,研究生,预科生...
由教职工派生出:老师,清洁工,食堂阿姨...
语法:
class 派生类名:访问限定符 基类名
{
//就像一个正常的类一样写
}
//Ex:
class Student:Public Person
{
}
//表示由Person派生出的Student类
2.公有派生与私有派生
公有派生:class a:public b(a是基类,b是派生类)
基类私有:不能访问
基类公有:可以访问,可以在类外访问
基类保护:可以访问,只能在类定义的成员函数内部访问
私有派生:class a:private b
基类私有:不能访问
基类公有:只能在类定义的成员函数内部访问
保护派生: class a:protect b
基类私有:不能访问
基类公有:将基类的公有变成派生类的保护
基类保护:变成派生类的保护
注:公有派生是主流,写程序是大多数用公有派生
3.派生类的构造函数与析构函数
派生类不能继承基类的构造函数与析构函数,其他(数据成员,函数成员)都可以继承
独有的新成员才是继承与派生的核心特征
语法&Ex:
//声明
Student(string I, string N, int B, string H, string S);
//函数体调用
Student::Student(string I, string N, int B, string H, string S) :Person(I, N, B, H)
{
StuNumber = S;
int i;
for (i = 0; i < 30; i++)
{
cs[i].courseName = "#";
cs[i].grade = 0;
}
}
}
}
//使用基类默认无参数构造函数不必显式给出
Student::Student()
{
int i;
StuNumber = "0";
for (i = 0; i < 30; i++)
{
cs[i].courseName = "#";
cs[i].grade = 0;
}
}
注意:在写派生类的构造函数时只需要写派生类自己的元素的赋值而不需要为基类元素赋值
//表白深深的学生类与人类
#include<iostream>
using namespace std;
class Person
{
string Id;//身份证号
string Name;
int Birthday;
string Home;//家庭住址
public:
Person(string I, string N, int B, string H);
Person();
~Person();
void SetName(const string);
string GetName() { return Name; }
void SetId(const string);
string GetId() { return Id; }
void SetBirth(const int);
int GetBirth() { return Birthday; }
void SetHome(const string);
string GetHome() { return Home; }
void PrintPerson();
};
void Person::PrintPerson()
{
cout << "Print the massage of a Person:"<<endl;
cout << "Id:" << Id << endl;
cout << "Name:" << Name << endl;
cout << "Birthday:" << Birthday << endl;
cout << "Home:" << Home << endl;
}
Person::~Person()
{
//string内部动态数组释放,由string自带的析构函数完成
}
void Person::SetName(string N)
{
Name = N;
}
void Person::SetId(string I)
{
Id = I;
}
void Person::SetBirth(int B)
{
Birthday = B;
}
void Person::SetHome(string H)
{
Home = H;
}
Person::Person(string I, string N, int B, string H)
{
Id = I;
Name = N;
Birthday = B;
Home = H;
}
Person::Person()
{
Id = "U";
Name = "U";
Birthday = 0;
Home = "U";
}
class course
{
public:
int grade;
string courseName;
};
//由person共有派生出student类
//基类:person 派生类:student
class Student :public Person
{
string StuNumber;//学号
course cs[30];//30门课的成绩
public:
//注意:派生类构造函数的声明
Student(string I, string N, int B, string H, string S);
Student();
~Student(){}//自动调用析构函数
int Setcourse(string c, int g);
void PrintStu();
};
void Student::PrintStu()
{
int i;
cout << "学号:" << StuNumber << endl;
PrintPerson();
for (i = 0; i < 30; i++)
if (cs[i].courseName != "#")
cout << cs[i].courseName << " " << cs[i].grade << endl;
cout << "--------the end--------" << endl;
}
int Student::Setcourse(string c, int g)
{
int i; bool f = true;
for (i = 0; i < 30; i++)
{
if (cs[i].courseName == "#")
{
cs[i].courseName = c;
cs[i].grade = g;
f = false;
break;
}
if (cs[i].courseName == c)
{
cs[i].grade = g;
break;
}
}
if (i == 30)return 0;//这个人修满了20门课
if (f)return 1;//修改之前的成绩
return 2;//登记新成绩
}
//注意:派生类构造函数的函数体,Person参数表不用类型
Student::Student(string I, string N, int B, string H, string S) :Person(I, N, B, H)
{
StuNumber = S;
int i;
for (i = 0; i < 30; i++)
{
cs[i].courseName = "#";
cs[i].grade = 0;
}
}
//使用基类默认无参数构造函数不必显式给出
Student::Student()
{
int i;
StuNumber = "0";
for (i = 0; i < 30; i++)
{
cs[i].courseName = "#";
cs[i].grade = 0;
}
}
int main()
{
string t;
int f, k;
Person p1("340201123456789123", "周星星", 19920922, "魔都市");
Person p2;
p2.SetId("340202123456789123");
p2.SetName("周浅");
p2.SetBirth(19920922);
p2.SetHome("上海市");
p1.PrintPerson();
p2.PrintPerson();
Student s1("340203123456789123", "卡布", 19920922, "魔都市", "123456");
cout << "请输入各科成绩" << endl;
while (1)
{
cin >> t;
if (t == "end")
break;
cin >> k;
f = s1.Setcourse(t, k);
if (f == 0)cout << "成绩表已满" << endl;
if (f == 1)cout << "修改成绩" << endl;
if (f == 2)cout << "登记成绩" << endl;
}
s1.PrintStu();
return 0;
}
多层派生及其构造函数的写法
#include<iostream>
using namespace std;
class Goods
{
int Price;
string Name;
string Factory;
int Quantity;
public:
Goods(int P, string N, string F, int Q);
void ShowG();
};
void Goods::ShowG()
{
cout << "Price:" << Price << endl;
cout << "Name:" << Name << endl;
cout << "Factory:" << Factory << endl;
cout << "Quantity:" << Quantity << endl;
}
Goods::Goods(int P, string N, string F, int Q)
{
Price = P;
Name = N;
Factory = F;
Quantity = Q;
}
class Elec:public Goods
{
string Color;
int Power;
public:
Elec(int P, string N, string F, int Q, string C, int Po);
void ShowE();
};
Elec::Elec(int P, string N, string F, int Q, string C, int Po) :Goods(P, N, F, Q)
{
Color = C;
Power = Po;
}
void Elec::ShowE()
{
cout << "Color:" <<Color<< endl;
cout << "Power:" <<Power<< endl;
}
class TV:public Elec
{
int Size;
string Form;
public:
TV(int, string, string, int, string, int, int, string);
void ShowT();
};
TV::TV(int P, string N, string F, int Q, string C, int Po,int size,string form) :Elec(P,N,F,Q,C,Po)
{
Size = size;
Form = form;
}
void TV::ShowT()
{
cout << "Show Television" << endl;
ShowG();
ShowE();
cout << "Size:" << Size << endl;
cout << "Form" << Form << endl;
cout << "-------end--------" << endl;
}
int main()
{
TV t(3969, "海信电视", "海信", 100, "Black", 120, 65, "超高清全面屏智能液晶智慧屏游戏电视机");
//海信:广告费了解一下
t.ShowT();
return 0;
}
4.赋值兼容规则:
1.派生类的对象可以赋值给基类的对象,实际上是把派生类中从基类继承来的值赋值给基类,但是反过来不行
2.派生类对象的地址可以赋给基类的指针变量,但只能通过这个指针访问由基类继承来的成员,反过来也不行
3.派生类对象可以初始化基类的引用,引用就是别名,但是这个别名只包含由基类继承来的成员
5.多态性与虚函数
virtual 返回类型 函数名(参数表)
{
//函数体
}
多态性:通过调用同一个函数名的函数,实现完全不同的功能
多态性是通过类继承关系和虚函数决定的,目的是建立一种通用的程序
如果虚函数在类内声明,类外定义,则定义时不能在+virtual
当一个类的某个类成员函数被定义为虚函数时,有该类派生出来的所有派生类中,该函数保持虚函数特征
在派生类中重新定义虚函数时(这正是使用虚函数的目的),可以不加virtual 但是重新定义时必须与原来的虚函数同名,并且参数表与返回值类型相同
如果虚函数不用virtual,就是同名覆盖函数,这样就不能实现运行时的多态性