01.继承
面向对象的四个特征之一、
1.继承方式
[注1]父类的private成员不会被子类继承
[注2]继承不可能升级,只能降级或平级
|继承方式|父类public成员|父类protected成员|父类private成员| | --- | --- || --- | --- | | 子类public继承| public | protected |不可见| | 子类protected继承|protected| protected| 不可见 | | 子类private继承| private | private | 不可见 |
2.类的派生与继承
1.父类A
class A{
public:
int nA;
A(){
nA = 1;
}
void funcA(){
cout << "funcA\n";
}
};
2.子类B继承父类A
class B:public A{
public:
int nB;
B(){
nB = 2;
}
void funcB(){
cout << "funcB\n";
}
};
3.子类C继承父类B
class C:public B{
public:
int nC;
C(){
nC = 3;
}
void funcC(){
cout << "funcC\n";
}
};
4.完整代码
[注]相当于子类C中可以使用自己的方法之外,还可以使用父类A和父类B的方法
#include <iostream>
using namespace std;
class A{
public:
int nA;
A(){
nA = 1;
}
void funcA(){
cout << "funcA\n";
}
};
class B:public A{
public:
int nB;
B(){
nB = 2;
}
void funcB(){
cout << "funcB\n";
}
};
class C:public B{
public:
int nC;
C(){
nC = 3;
}
void funcC(){
cout << "funcC\n";
}
};
int main() {
C c;
c.funcA();
c.funcB();
c.funcC();
cout << c.nA << endl;
cout << c.nB << endl;
cout << c.nC << endl;
}
3.父子同名成员并存
[注1]子类中同时有两个n和两个func()
[注2]直接使用默认指子类成员
[注3]如果需要使用父类的成员,需要使用父类名字空间显示指明
1.父类
class Father{
public:
//有一个n,有一个func()函数
int n = 1;
void func(){
cout<<"this is father"<<endl;
}
};
2.子类
class Son : public Father{
public:
//有一个n,有一个func()函数,还有一个set()函数
int n = 2;
void func(){
cout<<"this is son"<<endl;
}
void set(){
Father::n = -1;
n = -2;
}
};
3.main函数
Son son;
son.func();
son.Father::func();
cout << son.Father::n << endl;
cout << son.n << endl;
son.set();
son.func();
son.Father::func();
cout << son.Father::n << endl;
cout << son.n << endl;
4.完整代码
class Father{
public:
//有一个n,有一个func()函数
int n = 1;
void func(){
cout<<"this is father"<<endl;
}
};
class Son : public Father{
public:
//有一个n,有一个func()函数,还有一个set()函数
int n = 2;
void func(){
cout<<"this is son"<<endl;
}
void set(){
Father::n = -1;
n = -2;
}
};
int main(){
Son son;
son.func();
son.Father::func();
cout << son.Father::n << endl;
cout << son.n << endl;
son.set();
son.func();
son.Father::func();
cout << son.Father::n << endl;
cout << son.n << endl;
}
02.虚函数
虚函数:父类的虚函数可以在子类中被重写,即重新实现,但参数和返回值必须保持一致!
1.含有虚函数的类叫做虚类
class Human{
public:
virtual void say(){
cout << "I am human";
}
};
2.父类的虚函数可以在子类中被重写
class Student:public Human{
public:
void say(){
cout<<"I am student";
}
};
3.纯虚函数和抽象类
纯虚函数:不实现,仅声明为纯虚函数,留待子类里重写定义
含有纯虚函数的类叫做抽象类,仅有纯虚函数的类叫接口
1.纯虚函数
例如virtual float getS() = 0;
2.抽象类
class Shape{
public:
//纯虚函数
virtual float getS() = 0;
virtual float getC() = 0;
};
3.完整代码
#include <iostream>
using namespace std;
//抽象类
class Shape{
public:
//纯虚函数
virtual float getS() = 0;
virtual float getC() = 0;
};
class Circle : public Shape{
private:
float radius;
public:
Circle(float radius){
this->radius = radius;
}
float getS(){
return 3.14 * radius * radius;
}
float getC(){
return 2 * 3.14 * radius;
}
};
int main(){
Circle c(3.0);
cout << c.getC() << endl;
cout << c.getS() << endl;
return 0;
}
03.多态(重点)
利用虚函数重写+指针(重点)
指向子类对象的父类指针(重点)
1.多态的例子1
#include <iostream>
using namespace std;
class Human{
public:
virtual void say(){
cout << "I am human" << endl;
}
};
class Student : public Human{
public:
virtual void say(){
cout << "I am student"<< endl;
}
};
class CollegeStudent : public Human{
public:
virtual void say(){
cout << "I am college student"<< endl;
}
};
int main(){
CollegeStudent a;
Human* p1 = (Human*) &a;
Student* p2 = (Student*) &a;
CollegeStudent* p3 = &a;
p1->say();//I am college student
p2->say();//I am college student
p3->say();//I am college student
return 0;
}
2.多态的例子2
#include <iostream>
using namespace std;
class Human{
public:
virtual void toilet() = 0;
};
void func(Human *human){
human->toilet();
}
class Man : public Human{
public:
void toilet(){
cout << "我去男厕所" << endl;
}
};
class Woman : public Human{
public:
void toilet(){
cout << "我去女厕所" << endl;
}
};
class Non : public Human{
public:
void toilet(){
cout << "我去无性别厕所" << endl;
}
};
int main(){
Man man1,man2;
Woman woman1,woman2;
Non non1,non2;
func(&man1);
func(&man2);
func(&woman1);
func(&woman2);
func(&non1);
func(&non2);
return 0;
}
3.多态的意义:代码复用
动态联编 = 运行时多态 = 虚函数重写 = override
父类指定要做什么,子类来实现具体做法
动态联编:在编译时确定了要调用的是哪个函数(根据多个重载函数的参数列表确定)
#include <iostream>
using namespace std;
class Shape{
public:
virtual float getC() = 0;
virtual float getS() = 0;
};
class Circle : public Shape{
private:
float radius;
public:
Circle(float radius){
this->radius = radius;
}
float getC(){
return 2 * 3.14 * radius;
}
float getS(){
return 3.14 * radius * radius;
}
};
class Rectangle : public Shape{
private:
float a;
float b;
public:
Rectangle(float a,float b){
this->a = a;
this->b = b;
}
float getC(){
return 2*(a+b);
}
float getS(){
return a*b;
}
};
void display(Shape* ptr){
//此处实现了多态:通过父类指针调用子类重写的虚函数
cout << "C " << ptr->getC() << endl;
cout << "S " << ptr->getS() << endl;
}
int main(){
Circle circle(3.0f);
Rectangle rectangle(3.0,4.0);
display(&circle);
display(&rectangle);
return 0;
}
4.静态联编与动态联编
联编:确定具体要调用多个同名函数中的哪一个
上述虚函数重写+指针实现的多态特指运行时多态,与之相对的是编译时多态
1.
静态联编 = 编译时多态 = 函数重载 = overload
静态联编:在编译时确定了要调用的是哪个函数(根据多个重载函数的参数列表确定)
动态联编 = 运行时多态 = 虚函数重写 = override
动态联编:直到运行时才知道实际调用的是哪个函数(根据指针指向对象的实际身份)