封装
- 在private/protected 模块放置数据或者底层算法实现;
- 在public块提供对外接口,实现相应的功能调用;
- 类的封装案例
#include <iostream>
using namespace std;
// 类的定义 一般放在头文件
class Stu {
public: // 公有权限 接口
void setAge(const int& age) {
this->age = age;
}
const int& getAge() const {
return age;
}
private: // 数据封装
int age;
};
int main() {
// 创建对象
Stu s1;
s1.setAge(20);
cout << s1.getAge() << endl;
return 0;
}
继承
- 将一个类的成员变量、成员函数,应用到另一个类中,实现复用;
- 支持多继承,同python一样;而 java 仅支持单继承;
- 继承修饰符public、protected、private; 若不写修饰符,则默认private继承;
- public继承,基类中的public、protected、private 保持不变;
- protected继承,基类中的public、protected、private 变为protected、protected、private
- private继承, 基类中的public、protected、private全部变为private;
- 子类继承父类的所有函数,除了:
- 构造函数、拷贝构造函数;
- 析构函数;
- 友元函数、重载运算符
#include <iostream>
#include <string>
using namespace std;
// 基类
class People {
public:
string name;
People(const string& name, const int& age, const double& height) {
this->name = name;
this->age = age;
this->height = height;
cout << "父类完成初始化" << height << endl;
}
void printName() const {
cout << "name:" << name << endl;
}
void printAge() const {
cout << "age:" << this->age << endl;
}
void printHeight() const {
cout << "height:" << this->height << endl;
}
protected:
int age;
private:
double height;
};
// 类的定义 一般放在头文件
class Stu: public People { // 公有继承(经常使用)
public: // 可多个块
int num; // 若未放在public等修饰符下, 默认私有
Stu(const string& name, const int& age, const double&heigh): People(name, age, heigh){// 显式调用父类的有参构造,否则隐式调用父类的无参构造;
// 子类的构造 初始化
this->num = 102;
}
void printAge() const {// 子类方法中,只能访问继承的public/protected 成员,private成员无法访问,但可以通过父类的方法到父类代码中访问;
cout << "age:" << this->age << endl;
}
/*void printHeight() const {
cout << "height:" << this->height << endl;
} 不可访问继承的私有 */
};
int main() {
string name = "jack";
int age = 20;
double height = 23.5;
// 创建对象
Stu s1(name, age, height); // 父类的构造方法 完成对私有变量的初始化
s1.printName();
s1.printAge();
s1.printHeight(); // 在父类中访问私有
return 0;
}
多态
- 多个子类继承父类中的方法,可以分别实现方法的重写(改函数体);
- 父类中常采用 virtual 声明为虚函数,然后子类继承并重写;
- virtual 函数体赋值为=0,则为纯虚函数,所有的纯虚函数必须重写;
- 含有纯虚函数的类是抽象类,无法直接实例化,必须被继承;
子类重写普通的成员函数:
#include <iostream>
#include <string>
using namespace std;
// 基类
class People {
public:
void printCate() {
cout << "class People" << endl;
}
};
//
class Stu: public People { // 公有继承
public:
void printCate() { // 重写父类的 普通成员函数
cout << "class Stu" << endl;
}
void run(){
cout << "stu run." << endl; // 子类自定义函数
}
};
class Teacher : public People { // 公有继承
public:
void printCate() { // 重写父类的 普通成员函数
cout << "class Teacher" << endl;
}
};
class Worker : public People { // 公有继承
public:
void printCate() { // 重写父类的 普通成员函数
cout << "class Worker" << endl;
}
};
int main() {
People* ptr; // 向上造型:父类型指针 指向子类的对象(java中可以用父类声明变量,并赋值子类对象)
Stu stu;
Teacher tea;
Worker wk;
ptr = &stu; // 父类型的指针指向 子类Stu的对象
ptr->printCate(); // 指针调用子类对象的任何public成员,均走父类(除非重写虚函数)
ptr->run(); // 无法调用Stu子类中的成员
ptr = &tea;
ptr->printCate();
ptr = &wk;
ptr->printCate();
return 0;
}
输出:
把父类的普通成员函数加virtual关键字修饰,子类再次继承重写,向上造型指针调用子类对象的函数就可以走子类重写的虚函数;如下加virtual关键字:
// 基类
class People {
public:
virtual void printCate() {
cout << "class People" << endl;
}
};
//
class Stu: public People { // 公有继承
public:
virtual void printCate() { // 重写父类的 虚成员函数
cout << "class Stu" << endl;
}
};
class Teacher : public People { // 公有继承
public:
virtual void printCate() { // 重写父类的 普通成员函数
cout << "class Teacher" << endl;
}
};
class Worker : public People { // 公有继承
public:
virtual void printCate() { // 重写父类的 普通成员函数
cout << "class Worker" << endl;
}
};
抽象基类中的所有的
纯虚函数,必须重写:
#include <iostream>
#include <string>
using namespace std;
// 抽象基类(接口),无法直接实例化
class People {
public:
string name;
virtual void printCate() = 0; // 纯虚函数,没有函数体
virtual void setName(const string& name) = 0;
virtual const string& getName() = 0;
};
//
class Stu: public People { // 公有继承
public:
virtual void printCate() {
// 必须重写 抽象基类的 所有的纯虚函数;
cout << "Stu 实现printCate接口" << endl;
}
virtual void setName(const string& name) { // 必须重写 抽象基类的 所有的纯虚函数;
this->name = name;
}
virtual const string& getName() { // 必须重写 抽象基类的 所有的纯虚函数;
return this->name;
}
};
int main() {
Stu s;
s.setName("jack");
cout << s.getName() << endl;
return 0;
}