C++学习 day3

发布于 28 天前  17 次阅读


Day 3:类与对象

今天目标:理解 C++ 面向对象的基本思想,掌握类、对象、封装、成员函数、构造函数和成员初始化列表。


1、面向过程和面向对象

面向过程关注的是解决问题的步骤,常见写法是把任务拆成多个函数,按顺序执行。

例如:在开发板屏幕上画矩形:

open 打开屏幕
mmap 内存映射
draw_point 绘制像素点
munmap 解除映射
close 关闭文件

面向对象关注的是解决问题需要哪些对象,把数据和操作数据的函数放到对象内部。

例如:

定义 Screen 类,描述屏幕
创建 Screen 对象
定义 Rect 类,描述矩形
创建 Rect 对象
让 Rect 对象绘制到 Screen 对象上

一句话理解:

面向过程:围绕步骤写代码。
面向对象:围绕对象写代码。

2、面向对象三大特性

C++ 面向对象有三个核心特征:

封装:把数据和函数放到类中,隐藏内部实现,只暴露必要接口。
继承:在已有类基础上扩展新类。
多态:同一个接口,在不同对象上表现出不同效果。

当前阶段先重点掌握封装、类和对象


3、类和对象

3.1、类 class

类是 C++ 的自定义类型,用来描述一类事物的属性和行为。

属性:成员变量
行为:成员函数

例如坐标点:

class Point
{
public:
    void setX(int x);
    void setY(int y);
    void move(int x, int y);

    int getX() const;
    int getY() const;

private:
    int _x = 0;  // x 坐标
    int _y = 0;  // y 坐标
};

3.2、对象 object

对象就是用类创建出来的具体变量,也叫实例化对象

Point p1;  // 创建一个 Point 对象
Point p2;  // 再创建一个 Point 对象

简单理解:

类是图纸,对象是根据图纸造出来的具体东西。

4、封装和访问权限

封装就是把数据和函数放到类里面,并通过访问权限控制外部能不能直接访问。

常见写法:

private:放成员变量,保护数据
public :放成员函数,对外提供接口

访问权限:

public      公有,类外可以访问
private     私有,只能类内访问
protected   保护,类内和子类可以访问

示例:

Point p;
p.setX(100);  // 正确,通过 public 函数修改

// p._x = 100;  // 错误,_x 是 private,类外不能直接访问

class 和 struct 的区别

class  默认权限是 private
struct 默认权限是 public

实际开发中:

需要封装数据和行为:常用 class
只是简单保存数据:可以用 struct

5、类的声明和定义分离

标准 C++ 中,类一般分成三个文件:

point.hpp    类的声明
point.cpp    类的实现
main.cpp     类的使用

5.1、point.hpp:类的声明

#ifndef POINT_HPP
#define POINT_HPP

class Point
{
public:
    void setX(int x);
    void setY(int y);
    void move(int x, int y);

    int getX() const;
    int getY() const;

private:
    int _x = 0;  // x 坐标
    int _y = 0;  // y 坐标
};

#endif

头文件保护:

#ifndef POINT_HPP
#define POINT_HPP
...
#endif

作用是防止头文件被重复包含。

5.2、point.cpp:类的定义

#include "point.hpp"

void Point::setX(int x)
{
    _x = x;
}

void Point::setY(int y)
{
    _y = y;
}

void Point::move(int x, int y)
{
    _x = x;
    _y = y;
}

int Point::getX() const
{
    return _x;
}

int Point::getY() const
{
    return _y;
}

注意:

void Point::setX(int x)

这里的 Point:: 表示 setX 属于 Point 类。

类外定义成员函数时,必须写:

类名::函数名

5.3、main.cpp:类的使用

#include <iostream>
#include "point.hpp"

void printPoint(const Point& pos)
{
    std::cout << "x = " << pos.getX() << std::endl;
    std::cout << "y = " << pos.getY() << std::endl;

    // pos.setX(100); // 错误,const 引用只能调用 const 成员函数
}

int main()
{
    Point pos;

    pos.move(100, 200);
    printPoint(pos);

    return 0;
}

编译:

g++ main.cpp point.cpp -o app

6、只读成员函数 const

如果成员函数只读取数据,不修改成员变量,就应该在函数后面加 const

声明:

int getX() const;

定义:

int Point::getX() const
{
    return _x;
}

作用:

1. 表示这个函数不会修改对象内部数据
2. const 对象或 const 引用只能调用 const 成员函数
3. get 函数通常都写成 const 成员函数

错误示例:

int Point::getX() const
{
    _x = 100;  // 错误,const 成员函数不能修改成员变量
    return _x;
}

7、构造函数

构造函数是类中的特殊成员函数,用来在创建对象时初始化成员变量。

特点:

1. 函数名和类名相同
2. 没有返回类型
3. 创建对象时自动调用
4. 可以重载
5. 如果没有写构造函数,编译器会自动生成默认构造函数

示例:

class Point
{
public:
    Point()
    {
        _x = 0;
        _y = 0;
    }

    Point(int x, int y)
    {
        _x = x;
        _y = y;
    }

private:
    int _x;
    int _y;
};

使用:

Point p1;          // 调用无参构造函数
Point p2(100, 200); // 调用有参构造函数
Point p3{1, 2};     // C++11 写法

注意:

Point p4();  // 这不是创建对象,而是声明一个函数
Point p5{};  // 这是创建对象

默认构造函数

默认构造函数指不传参数也能调用的构造函数

两种常见形式:

Point();                      // 无参构造
Point(int x = 0, int y = 0);  // 参数都有默认值

匿名对象

直接调用构造函数会产生一个没有名字的临时对象,也叫匿名对象。

foo(Point(100, 200));  // 用临时对象作为函数参数

8、成员初始化列表

成员初始化列表写在构造函数参数列表后面,用冒号 : 开始。

格式:

类名(参数列表) : 成员1(初值), 成员2(初值)
{
}

示例:

class Point
{
public:
    Point(int x, int y) : _x(x), _y(y)
    {
    }

private:
    int _x;
    int _y;
};

这比在构造函数体里赋值更推荐,因为它是初始化,效率更高。

必须使用成员初始化列表的情况

1. 成员变量是 const 常量
2. 成员变量是引用
3. 成员对象没有默认构造函数

示例:

class Other
{
public:
    Other(int value) : _value(value)
    {
    }

private:
    int _value;
};

class Demo
{
public:
    Demo(int x, int y) : _x(x), _y(y), _r(_x), _oth(100)
    {
    }

private:
    int _x;
    const int _y; // const 成员必须初始化
    int& _r;      // 引用成员必须初始化
    Other _oth;   // Other 没有默认构造函数,必须初始化
};

9、总结

1. 类是自定义类型,用来描述一类事物的属性和行为。
2. 对象是由类创建出来的具体变量。
3. 封装是把数据隐藏起来,通过 public 函数安全访问。
4. public 可以类外访问,private 只能类内访问。
5. class 默认 private,struct 默认 public。
6. 类的声明通常写 .hpp,定义通常写 .cpp。
7. 类外定义成员函数要写 类名::函数名。
8. get 函数通常写 const,因为它只读取数据。
9. 构造函数在创建对象时自动调用,用于初始化成员变量。
10. 成员初始化列表更推荐,const 成员、引用成员、无默认构造的成员对象必须用它。

一句话记忆:

类负责描述,对象负责使用;封装负责保护数据,构造函数负责初始化对象。

"When faced with uncertainty, ask the spring breeze."