面向对象
- 基本思想:将现实的需求抽象化为代码中的一个类,并为这个类赋予基于的属性和方法;当需要使用这个类的时候,通过定义该类的实例化对象来实现
- 基本写法:
class 类名{
访问修饰符: //解释见下
成员变量;
成员方法;
};
- 访问修饰符:
- 用来指定成员属性和方法的可见性和访问权限,包括以下三种
- public:公有,开放权限
- private:私有,仅允许类内访问
- protected:受保护,仅允许类及该类的派生类(子类)内访问
- 面向对象三大特性
封装
- 为什么要封装
- 如何封装
- 第一步,将想要保护的属性修饰为
private
- 第二步,如果有需求,在类内定义对应的读取和修改方法,之后所有对想保护属性的读取和修改都要通过对应方法,在对应方法中可以添加限定条件,满足时才可进行读取或修改
Const关键字
构造函数
- 类的构造函数和结构体的构造函数类似,有如下特点:
- 函数名和类名相同
- 没有返回类型和返回值
- 实例对象创建时自动调用
- 示例,其中
const string& personName
使用引用&的目的是避免变量值拷贝占用内存、降低效率,使用const的目的是保证该参数不会在函数体内被改变
class Person {
private:
int age;
string name;
public:
// 默认构造函数
Person() {
age = 20;
name = "Tom"
}
// 带参数的构造函数
Person(int personAge, const string& personName) {
age = personAge;
name = personName
}
}
int main() {
// 使用默认构造函数创建对象
Person person1;
// 使用带参数的构造函数创建对象
Person person2(20, "Jerry");
return 0;
}
- 除了上述示例,还可以使用成员初始化列表的方式书写构造函数,如下,在这里,
age(personAge), name(personName)
表示将personAge
的值赋给age
成员变量, 将personName
的值赋给name
, 从而完成了成员变量初始化。
Person(int personAge, const string& personName) : age(personAge), name(personName) {
}
继承
- 为什么要用继承?
- 怎么实现继承
class son : 访问修饰符 father {}
- 子类中对于父类方法的重写
- C++里,重写类的方法需要添加关键字
override
,该关键字放在函数形参列表后,如double calculate() override {}
多态
class Shape {
public:
virtual double calculateArea() const = 0;
};
class Circle : public Shape {
private:
int radius;
public:
double calculateArea() const override {
return 3.14 * radius * radius;
}
};
class Rectangle : public Shape {
private:
int width;
int height;
public:
// 构造函数,用于初始化 width 和 height
Rectangle(int w, int h) : width(w), height(h) {}
// width * height 的结果是整数,但 calculateArea 方法的返回类型是 double
// 为了确保结果是一个浮点数,使用 static_cast<double> 将其显式转换为 double 类型
double calculateArea() const override {
return static_cast<double>(width * height);
}
};
- 这里使用virtual在父类中定义了一个虚函数,而= 0表示这是一个纯虚函数,即定义的函数在基类中没有实现,但是要求它的派生类都必须提供这个函数的实现,这种抽象的方法使得 Shape 类成为一个抽象基类,不能被实例化,只能被用作派生其他类的基类。
- 然后两个派生类 Circle 和 Rectangle则是重写了 calculateArea 方法,它们提供了各自的实现,有着不同的计算逻辑