C++面向对象整理(1)之初识类和对象

C++面向对象整理(1)之初识类和对象

注:整理一些突然学到的C++知识,随时mark一下
例如:忘记的关键字用法,新关键字,新数据结构



提示:本文为 C++ 中 类定义、成员函数 的写法和举例


一、类的定义

  类(class)就是自定义一种数据结构,这个数据结构就是更高级版本的C的结构体struct,拥有很多属性数据,但更一步相比结构体,类还新增了很多函数(称为成员函数、或方法),这些函数可以把这些属性数据当成传递的参数施加运算(如初始化赋值)或操作,而且还可以传新的参数,同时这些函数可以通过访问权限控制是否可以传入/访问这些数据。
在C++中,定义类(class)的基本语法如下:

class ClassName {  
     访问权限:
              类内给出类的成员变量的声明  
     访问权限:
     		  类内给出类的成员函数的声明或实现  
};

//类外定义成员函数,使用冒号
返回类型 ClassName::成员函数的实现

注意工程上一般将类分文件编写定义,h文件中写类的声明,源文件中写类的函数的具体实现。当然也可以一次性写在一个文件里。

类的成员函数可以分为以下几种类型:

(1)普通成员函数:这是最常见的成员函数类型,它们执行类的特定操作,并且通常依赖于类的特定实例(对象)来执行。

(2)构造函数:构造函数是一种特殊的成员函数,它在创建类的对象时被自动调用,用于初始化对象的成员变量。构造函数的名字必须与类名相同,并且不能有返回类型。构造函数可以重载,可以有多个构造函数,以应对不同的初始化需求(这个非常重要,这里后面讲)。

(3)析构函数:析构函数也是特殊的成员函数,它在对象的生命周期结束时被调用,用于执行清理工作、释放分配的内存等。析构函数的名字是类名前加上波浪号 ~。

(3)赋值操作符重载函数:这是重载的赋值操作符就是等于号 = ,用于实现对象之间的赋值操作。(后面讲)

(4)取地址操作符重载函数和const修饰的取地址操作符重载函数:这些是重载的取地址操作符(&),分别用于获取对象的地址和const对象的地址。

(5)virtual的成员函数:其地址指向vtable(虚函数表)中的位置,通常用于实现多态。

(6)static的成员函数:不依赖于类的对象而存在的函数,也不依赖于类的对象而调用。关于static和const
(7)const的成员函数:表示该函数不能擅自改变成员变量的值。

1、类成员的访问权限

类的访问权限有三种:

public:公开的,表示这个成员可以在任何地方被访问。
protected:受保护的,表示这个成员可以在该类其派生类中被其访问,但不能被该类的对象通过点运算符访问。
private:私有的,表示这个成员只能在类的内部被访问,类的外部无法直接访问。如果没有明确指定访问权限,那么默认是private

2、类定义示例

现在,我们来定义一个坐标点类Point,包含空间三维坐标(x, y, z)并提供提取GET或设置SET坐标值和一个求距离的接口distanceTo(方法),假设定义的距离是两点之间的欧几里得距离。

(1)类内定义

#include <cmath> // 用于sqrt函数 

class Point {  
public:  
	Point(double x, double y, double z) {  
    // 这里构造函数直接赋值  
    x_ = x;  
    y_ = y;  
    z_ = z;  
}  
   
    // 获取x坐标  
    double getX() const { return x_; }  
  
    // 获取y坐标  
    double getY() const { return y_; }  
  
    // 获取z坐标  
    double getZ() const { return z_; }  
  
    // 设置x坐标  
    void setX(double x) { x_ = x; }  
  
    // 设置y坐标  
    void setY(double y) { y_ = y; }  
  
    // 设置z坐标  
    void setZ(double z) { z_ = z; }  
  
    // 计算两点之间的欧几里得距离  
    double distanceTo(const Point& other) const {  
        double dx = x_ - other.x_;  
        double dy = y_ - other.y_;  
        double dz = z_ - other.z_;  
        return std::sqrt(dx * dx + dy * dy + dz * dz);  
    }  
  
private:  
    // 坐标变量  
    double x_;  
    double y_;  
    double z_;  
};

构造函数也可以写成以下初始化列表形式,也可用于用于初始化

Point(double x = 0.0, double y = 0.0, double z = 0.0)   
    : x_(x), y_(y), z_(z) {}  

(2)类外定义成员函数

比如我们要将Point类分为头文件(.h)和源文件(.cpp)分开编写,类外定义不一定要分开写,只是工程上一般这样写。

首先是头文件Point.h:

// Point.h  
#ifndef POINT_H  
#define POINT_H  
  
#include <cmath> // 包含cmath库以使用std::sqrt  
  
class Point {  
public:  
    // 构造函数,用于初始化坐标  
    Point(double x = 0.0, double y = 0.0, double z = 0.0);  
  
    // 获取x坐标  
    double getX() const;  
  
    // 获取y坐标  
    double getY() const;  
  
    // 获取z坐标  
    double getZ() const;  
  
    // 设置x坐标  
    void setX(double x);  
  
    // 设置y坐标  
    void setY(double y);  
  
    // 设置z坐标  
    void setZ(double z);  
  
    // 计算两点之间的欧几里得距离  
    double distanceTo(const Point& other) const;  
  
private:  
    // 坐标变量  
    double x_;  
    double y_;  
    double z_;  
};  
  
#endif // POINT_H

然后是源文件Point.cpp:

// Point.cpp  
#include "Point.h"  
  
// 构造函数实现  
Point::Point(double x = 0, double y = 0, double z = 0) {  
    // 这里直接赋值  
    x_ = x;  
    y_ = y;  
    z_ = z;  
}  
  
// 获取x坐标  
double Point::getX() const {  
    return x_;  
}  
  
// 获取y坐标  
double Point::getY() const {  
    return y_;  
}  
  
// 获取z坐标  
double Point::getZ() const {  
    return z_;  
}  
  
// 设置x坐标  
void Point::setX(double x) {  
    x_ = x;  
}  
  
// 设置y坐标  
void Point::setY(double y) {  
    y_ = y;  
}  
  
// 设置z坐标  
void Point::setZ(double z) {  
    z_ = z;  
}  
  
// 计算两点之间的欧几里得距离  
double Point::distanceTo(const Point& other) const {  
    double dx = x_ - other.x_;  
    double dy = y_ - other.y_;  
    double dz = z_ - other.z_;  
    return std::sqrt(dx * dx + dy * dy + dz * dz);  
}

在这个Point类中,我们定义了:

一个构造函数,用于初始化坐标值。
getX(), getY(), getZ()方法,用于获取坐标值。
setX(), setY(), setZ()方法,用于设置坐标值。
distanceTo()方法,用于计算当前点到另一个点的欧几里得距离。
x_, y_, z_是私有成员变量,只能在Point类内部访问,而公开的getX(), getY(), getZ(), setX(), setY(), setZ()方法提供了对私有成员变量的访问接口。distanceTo()方法使用了私有成员变量来计算距离。这样定义的类既保证了成员变量的封装性(只有类内部才能直接访问),又提供了公共接口供外部使用。

3、类对象(实例)的定义及初始化

有了自己定义好的class类型,我们就可以用它声明和初始化属于这个类的对象变量(实例 instance),比如,对于内置的数据类型有 int a = 1; int a; int b = a; 那么类该如何对应的实现上述初始化方式呢:
基于上面的类class Point来说明
于是:
(1)对应int a;

Point p1; 

执行这段代码时会立即调用定义的构造函数创建一个Point对象,坐标默认为(0, 0, 0)。

(1)对应int a = 1;

因为类有很多数据成员,但又不可能像python写作Point A ={1,2,3} 这么简单(好吧其实后面C++也引入了花括号的写法),因为编译器压根不知这是啥,所以必须引入构造函数来给每个数据成员初始化赋值:

Point p2(1.0, 2.0, 3.0); // 使用带参数的构造函数创建一个Point对象,坐标为(1.0, 2.0, 3.0)

(2)对应int b = a;

Point p3(p2); // 使用拷贝构造函数创建一个Point对象,坐标也为(1.0, 2.0, 3.0)
或者
Point p3 = p2; //若有重载的等号赋值

关于拷贝构造和重载运算符这里先不讲,记住这个语法形式即可。

(3)对应 int *p = & a;

Point * pointerP = & p3

但一般使用new关键字或智能指针在堆上动态创建对象(关于这两个详见前面关于动态内存new关于智能指针

Point* pointerP = new Point(7.0, 8.0, 9.0); // 在堆上动态创建一个Point对象,并返回指向它的指针

4、类的匿名对象

匿名对象(也称为临时对象)是指没有显式名称的对象。对于类来说,这意味着创建了一个类的对象,但没有给它一个变量名来用它。匿名对象通常用于那些只需要执行一次操作,如执行一次某个成员函数,并且之后不再需要引用的情况。匿名对象会在执行完构造函数或者调用成员函数后立即被销毁。一个类A的匿名对象的格式是A()或A(paras)

例如,上面的Point类,我只想执行一次计算距离函数来得到两个点的距离dist

double dist = Point(-1,-2,-3).distanceTo(p2);//Point(-1,-2,-3)就是匿名对象

再比如有一个简单的类,它有一个输出消息的成员函数:

class MessagePrinter {
public:
    void printMessage(const std::string& msg) const {
        std::cout << msg << std::endl;
    }
};

可以创建一个匿名对象并立即调用其成员函数,如下所示:

MessagePrinter().printMessage("Hello, World!");

本例MessagePrinter() 创建了一个 MessagePrinter 类的匿名对象,并立即调用了其 printMessage 成员函数。由于这个对象没有名称,因此它只存在于这次函数调用期间。当 printMessage 函数执行完毕后,这个匿名对象就会被销毁

5、类对象的内存分配

成员变量和成员函数在内存中的存储和访问方式有着根本的区别。在内存中,一个类的对象通常按照成员变量的声明顺序进行布局。成员变量的内存布局可能受到内存对齐规则的影响,以确保访问效率。而成员函数则不直接占用对象的内存空间,它们的代码在程序的代码段中成员变量是每个对象特有的,而成员函数则是类共有的。

成员变量
成员变量是类定义中的一部分,它们存储在类的对象中。当你创建一个类的对象时,系统会在内存中为对象的每个成员变量分配空间。这些空间通常位于堆(如果使用new操作符)或栈(如果在函数内部创建对象)上。每个对象都有自己的成员变量副本,因此修改一个对象的成员变量不会影响其他对象的成员变量,除非这些对象之间通过引用或指针相互关联。

成员函数
成员函数也是类定义中的另一部分,但它们并不直接存储在类的对象中。相反,成员函数通常存储在代码段中,这是程序的可执行部分。每个成员函数只有一个代码实例,无论创建了多少个类的对象,只有一块内存成员函数。当对象调用成员函数时,函数代码被执行,并且函数的参数(如果有的话)以及类的this指针(指向调用该函数的对象的指针)被传递给函数。

this指针(后面讲)
在成员函数内部,可以通过this指针访问调用该函数的对象的成员变量。this指针是一个隐含的指针,它指向调用成员函数的对象。通过this指针,成员函数可以访问和修改对象的成员变量。

静态成员
静态成员变量和静态成员函数是类的特殊成员。静态成员变量不属于任何特定的对象实例,而是属于类本身。它们只存储一份,而不是每个对象一份。静态成员函数也是属于类本身的,它们不能访问非静态成员变量(除非通过对象或引用),但可以直接访问静态成员变量和其他静态成员函数。

  • 34
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值