文章目录
🌿前言:本系列笔记是主要是对于谭浩强的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;
}
八、继承和组合
在一个类中以另一个类的对象作为数据成员,称为类的组合