一,封装
定义:
通常会将类中属性和一些方法进行隐藏。通常是把属性设为私有,这时访问就需要通过公共的接口。可以控制属性读和写的权限,提高程序的安全性。
练习:
#include <iostream>
using namespace std;
class Person{
private: //私有权限 只能类中访问
string name; //姓名 可读,可写
string address; //地址 只读
string password="123456"; //密码 只写
public:
string getName(){
return name;
}
void setName(string str){
name=str;
}
void getAddress(){
cout<<"定位地址为山东"<<endl;
}
void setPassword(string str){
password=str;
}
};
int main()
{
Person p;
//p.name="小明"; //name是私有权限 类外访问不到
p.setName("小明");
p.setPassword("123789");
cout<<"姓名"<<p.getName()<<endl; //姓名小明
p.getAddress(); //定位地址为山东
}
二,继承
1.定义:
在已存在类的基础上,创建新的类。会拥有原有类的一些特性。通常会在原有类基础上做修改和增加操作。
已经存在的类成为父类或基类
新创建的类称为子类或派生类
练习:
#include <iostream>
using namespace std;
class Father{
public:
string first_name="李";
void work(){
cout<<"我是名厨师"<<endl;
}
};
class Son:public Father{ //公共继承
};
int main()
{
Son s;
cout<<s.first_name<<endl;
s.work();
}
函数隐藏:如果子类中给出与父类同名的函数,父类中所有同名函数都被隐藏。如果需要访问需要父类的作用域限定符的方式进行访问
举例:
#include <iostream>
using namespace std;
class Father{
public:
string first_name="李";
void work(){
cout<<"我是名厨师"<<endl;
}
};
class Son:public Father{ //公共继承
public: //权限不写默认是私有的
void work(){
cout<<"嵌入式工程师"<<endl;
}
void study(){
cout<<"喜欢学习"<<endl;
}
};
int main()
{
Son s;
cout<<s.first_name<<endl;
s.work();
s.Father::work();//可以访问被隐藏的父类函数
s.study();
}
2.继承注意事项
父类的构造函数不会继承下来
子类一定要直接或者间接的调用父类的构造函数。来完成从父类继承过来数据的初始化。如果子类不写明如何调用父类的构造函数,这时会调用父类无参的构造函数,如果父类中没有无参的构造函数,这时就会报错
举例:
#include <iostream>
using namespace std;
class Father{
private:
string name;
public:
Father(string name){
this->name=name;
}
void work(){
cout<<name<<"是名厨师"<<endl;
}
};
class Son:public Father{ //公共继承
};
int main()
{
Son s;
s.work();
}
3.权限
注意:权限不写默认是私有
不同权限访问情况
不同权限的成员,在不同位置的可访问情况
public 本类中可以可以访问 在子类中可以访问 在全局中可以访问
protected 本类中可以可以访问 在子类中可以访问 在全局中不可以访问
private 本类中可以可以访问 在子类中不可访问 在全局中不可以访问
不同权限的继承
任何权限的继承,私有权限成员继承之后,都不能直接访问
排除私有成员的情况下,公有继承全不变,保护继承变保护,私有继承变私有
4.多继承
多继承使用
一个类有多个基类,这时就是多继承 。实际开发中要避免使用多继承,多继承造成的问题复杂度高于便利性
#include <iostream>
using namespace std;
class Bed{
public:
void lay(){
cout<<"可以躺着"<<endl;
}
};
class Sofa{
public:
void sit(){
cout<<"可以坐着"<<endl;
}
};
class SofaBed:public Bed,public Sofa{
};
int main()
{
SofaBed sf;
sf.lay();
sf.sit();
}
多继承二义性问题
不同的基类拥有同名成员,此时派生类的调用会出现二义性问题,可以通过类名加作用域限定符的方式进行区分,避免二义性
#include <iostream>
using namespace std;
class Bed{
public:
void lay(){
cout<<"可以躺着"<<endl;
}
void position(){
cout<<"放在卧室"<<endl;
}
};
class Sofa{
public:
void sit(){
cout<<"可以坐着"<<endl;
}
void position(){
cout<<"放在客厅"<<endl;
}
};
class SofaBed:public Bed,public Sofa{
};
int main()
{
SofaBed sf;
sf.lay();
sf.sit();
//sf.position(); //从Bed和Sofa都继承了position()函数,调用时会不明确
sf.Bed::position();
sf.Sofa::position();
}
三,多态
多态概念和条件(掌握)
字面意思多种状态,可以简单概括就是一个接口,多种状态。动态的决定程序调用的代码
静态多态:编译期就确定下来应该调用哪个方法。比如函数重载,运算符重载
动态多态:运行的时候,才确定具体调用哪个函数。这时需要用到虚函数
运行时多态的三个条件:
公有继承
基类的指针或者引用指向派生类对象
派生类覆盖基类的虚函数
运行时多态的三个条件:
公有继承
基类的指针或者引用指向派生类对象
派生类覆盖基类的虚函数
#include <iostream>
using namespace std;
class Animal{
public:
void eat(){
cout<<"吃东西"<<endl;
}
};
class Cat:public Animal{
public:
void eat(){
cout<<"吃鱼"<<endl;
}
};
class Dog:public Animal{
public:
void eat(){
cout<<"吃狗粮"<<endl;
}
};
//void test1(Cat& c){
// c.eat();
//}
//void test2(Dog& d){
// d.eat();
//}
//所有Aniamal类的派生类都可以传入,实现了公共接口
void test(Animal& a){
a.eat();
}
void test(Animal* a){
a->eat();
}
int main()
{
Cat cat1;
test(cat1); //吃东西
Dog dog1;
test(dog1); //吃东西
Dog dog2;
test(&dog2);//吃东西
}
多态的实现(掌握)
运行时多态的实现需要用到虚函数,虚函数就是virtual关键字修饰的函数
函数覆盖和虚函数的特点:
1.当函数覆盖成功时,虚函数具有传递性
2.C++11中可以在派生类的新覆盖的函数后增加override关键字进行覆盖是否成功的验证
3.成员函数与析构函数可以定义为虚函数,静态成员函数与构造函数不可以定义为虚函数,因为构造函数不能被派生类继承,也就没办法覆盖重写。静态成员函数与对象无关
如果成员函数的声明与定义分离,virtual关键字只需加在声明处