继承设计
1.回顾类和对象的创建
定义学生类Student,包含私有数据成员:num(学号)、name(姓名,字符数组)、age(年龄);公有成员函数:Student(构造函数)、~Student(析构函数),使用构造函数为Student类对象的数据成员赋值(name使用动态内存分配),在析构函数中释放动态分配的内存,显示函数display(显示学生信息)。
法一:
#include<iostream> #include<string> using namespace std; class Student { private: long num; char* name; int age; public: Student() {} Student(long nu, char* na, int a) :num(nu), name(na), age(a) {} ~Student() {} void display() { cout << "学号:" << num << " " << endl << "姓名:" << name << endl << "年龄:" << age << endl; } }; int main() { char ch[] = "李丽"; Student* ptr = new Student();//① ptr = new Student(3018314, ch, 18);//② Student* ptr1 = new Student(2018314, ch, 18);//③ ptr->display();//这个指针对应①②,需要无参数的构造函数 cout << endl; ptr1->display();//这个指针对应③,调用声明的有参构造函数即可 return 0; }
法二:(多条信息)
#include <iostream> #include <string> using namespace std; class student { private: int num; char name[30]; int age; public: student(int nu, const char* na, int ag) { num = nu; strcpy_s(name, na); age = ag; } ~student() {} void display(student** ss, int total) { student* sp = ss[0]; int i = 0; while (i < total) { cout << "(" << i + 1 << ") " << sp->num << " " << sp->name << " " << sp->age << endl; i++; sp = ss[i]; } sp = NULL; } int main() { student* ss[4]; for (int i = 0; i < 4; i++) { ss[i] = NULL; } ss[0] = new student(2018311, "李丽", 18); ss[1] = new student(2018312, "张三", 18); ss[2] = new student(2018313, "王明", 19); ss[3] = new student(2018314, "李四", 19); ss[0]->display(ss, 4); return 0; }
2、思考代码
#include<iostream> #include<string> using namespace std; class person { //person基类 private: string name; protected: int age; public: void printname(); void setname(string); person() { name = "基类test"; cout << "name=" << name << " 基类构造函数执行" << endl; } person(string name1) { name = name1; cout<<"name="<<name<<" 基类构造函数执行"<<endl; } ~person() { cout<<"name="<<name<<" 基类person析构函数执行"<<endl; } }; void person::printname() { cout << "基类name=" << name << endl; } void person::setname(string name1) { name = name1; } class student :public person {//student 继承person 是派生类 private: int no; float score; person p1; protected: string sex; public: void output(); student():person("mm"),p1("4") { no = 1; score = 80.0; age = 20; cout << "no=" << no << " 派生类构造函数执行" << endl; } ~student() { cout<<"no="<<no<<" "<<"派生类析构函数"<<endl; } }; void student::output() { printname(); cout << "age=" << age << endl; } void main() { student st; //说明在创建st对象时,调用了哪个构造函数 //是否调用了基类构造函数?如果是,调用的是哪个基类的构造函数 cout << "st----" << endl; st.printname(); }
总结:
析构函数的调用顺序与构造函数相反。
构造函数的调用从基类开始再到派生类,“从外到里”;
而析构函数“从里到外”,先调用派生类的析构函数,再一步步到基类。即派生类本身的析构函数->对象成员析构函数->基类析构函数。
3、编程
定义一个Teacher类,包含私有数据成员int num、string name、char sex,构造函数Teacher()和有参构造函数Teacher(int num,string name,char sex),成员函数input实现数据成员的输入,成员函数数output实现数据成员输出到屏幕上。定义Professor类,包含私有数据成员int rank,并公有继承Teacher类;通过构造函数初始化所有数据成员(包括继承来的数据成员),成员函数Pinput实现所有数据成员的输入(包括继承的数据成员),Pouput实现所有数据成员的输出。
#include<iostream> #include<string> using namespace std; class Teacher { private: int num; string name; char sex;//string public: Teacher() {} Teacher(int nu, string na, char s) :num(nu), name(na), sex(s) {} void input() { cout << "请输入学号,姓名,性别:" << endl; cin >> num >> name >> sex; } void output() { cout << "学号:" << num << " " << "姓名:" << name << " " << "性别:" << sex << endl; } }; class Professor :public Teacher { private: int rank; public: Professor() {} Professor(int n1, string n2, char a1, int r) :Teacher(n1,n2,a1), rank(r) {} //Professor() {}
//在派生类构造函数的初始化列表里调用基类的构造函数 //Professor(int rank) {
//Teacher();派生类的构造函数中继承基类的构造函数
//this->rank = rank;
// }
//void Pinput();
//void Poutput(); void Pinput() { input(); cout << "请输入排名:" << endl; cin >> rank; } void Poutput() { output(); cout << "排名:" << rank; } }; int main() { Professor s; s.Pinput(); s.Poutput(); return 0; }
注意:
char型数据是计算机编程语言中只可容纳单个字符的一种基本数据类型。
声明sex 为char类型,所以性别输入“女”会多占字符,导致rank无法输入,
将其声明为string类型就可解决此问题。
4、多继承应用
派生类名::派生类名(参数表:基类1的形参,基类2的形参,……,基类n的形参,本类的形参):基类名1(基类1的形参),基类名2(基类2的形参),……,基类名n(基类名n的形参)
{
本类成员初始化赋值语句;
}
例:
#include<iostream> #include<string> using namespace std; class A { private: int a; public: A(int x) { a = x; } void setA(int x) { a = x; } void showA() { cout << "a=" << a << endl; } }; class B { private: int b; public: B(int x) { b = x; } void setB(int x) { b = x; } void showB() { cout << "b=" << b << endl; } }; class C :public A, private B //公有继承A,私有继承B { private: int c; public: C(int a, int b, int c1) :A(a), B(b) //派生类构造函数初始化 { c = c1; } void setC(int x, int y) { c = x; setB(y); //通过B类的成员函数setB()为B类的私有成员b赋值 } void showC() { cout << "c=" << c << endl; } void showABC() { showA(); //能否改成 cout<<"a="<<a<<endl; showB(); //能否改成 cout<<"b="<<b<<endl; cout << "c=" << c << endl; } }; void main() { C obj(1, 2, 3); cout << "显示a,b,c" << endl; obj.showABC(); /*cout<<"显示a"<<endl; obj.showA(); cout<<"显示b"<<endl; obj.showB(); */ }
在类C中的showABC()函数中,能否将
showA(); 改成 cout<<"a="<<a<<endl;
showB(); 改成 cout<<"b="<<b<<endl;
答:不能,因为a,b是基类的私有成员,在类C中不可访问。
5、编程实现:(多继承)
(1)定义“点”类Point。包含数据成员x,y(分别表示点的横纵坐标),具有构造函数;成员函数void showpoint()输出x,y,int getx()、int gety()分别返回x、y的值,void setxy()给x,y赋值。
(2)定义半径类Radius。包含数据成员r,具有构造函数;成员函数void setr(int r1)设置r的值,int getr()返回r的值。
(3)由Point类、Radius类派生出圆类Circle,在其构造函数中给基类数据成员赋值,成员函数double area()返回圆的面积,void shouwcircle()输出点的坐标和圆的面积。
(4)在main函数中,定义Circle类的对象,并调用setxy,setr, showcircle函数。
#include<iostream> using namespace std; #define PI 3.141592 class Point { private: int x, y; public: Point() {} void showpoint() { cout << "x=" << x << endl; cout << "y=" << y << endl; } int getx() { return x; } int gety() { return y; } void setxy(int xx, int yy) { x = xx; y = yy; } }; class Radius { private: int r; public: Radius() {} void setr(int r1) { r = r1; } int getr() { return r; } }; class Circle :public Point, public Radius { //多继承 public: Circle() {} Circle(int xx, int yy) { setxy(xx, yy); } double area() { return getr() * getr() * PI; } void showcircle() { cout << "圆心坐标为:" << "(" << getx() << "," << gety() << ")" << endl; cout << "圆的面积为:" << area() << endl; } }; void main() { int x, y; int r; cout << "输入圆心坐标x y:"; cin >> x >> y; cout << "输入半径r:"; cin >> r; Circle c; c.setxy(x, y); c.setr(r); c.showcircle(); }