从C的struct到C++的class:封装、this指针、三大特性入门

引言

前面我们学了C++与C的关键区别(引用、重载、命名空间等),但这些还只是"语法糖",C++真正的核心是面向对象编程(OOP) ,而OOP的基石就是**类(class)和对象(object)。**本篇为类和对象入门篇,包括定义、访问限定符、实例化、this指针等。

如果想详细深入学习C++类和对象以及其他内容,可以关注我,后面还会更加深入的去为大家剖析C++类和对象的内容,并且全部免费。

从C的 struct 到C++的 class

首先,学过C语言的同学们对于 struct 结构体 肯定不陌生,它可以定义一个新的自定义类型,还能存放成员变量,但是呢 struct 又太过于简陋,只能存放数据,不能存放函数方法;并且没办法控制权限,程序员可以任意访问结构体中的数据。

因此,C++就将我们C语言中的结构体(Struct) 升级成了类(Class)

比如我们想去手动实现一个栈,在C语言中,我们需要先用结构体 定义一个栈(只能存放数据),再去另外写一些方法实现对栈的各种操作;但在C++当中,我们可以用一个定义一个 类型 Stack,存放数据以及各种函数,将整个栈有关的内容封装 到一个类中。这样的编程方式也符合我们面向对象编程思想。

cpp 复制代码
// C语言
struct Student {
    char name[20];
    int age;
};
void PrintStudent(const struct Student* s) {
    printf("%s, %d\n", s->name, s->age);
}
// 数据和操作是分离的
cpp 复制代码
// C++风格
class Student {
    // 默认private
    char name[20];
    int age;
public:
    void Print() {
        cout << name << ", " << age << endl;
    }
};
// 将数据和方法打包起来

类的定义(strcut、class)

类的定义 方式有两种,一种是用class ,一种是struct。 这时候就有人会问了:struct 不是用来定义结构体的吗?

是的,在C++中 struct 兼容了C中的 struct 用法,在C的基础上还可以包含成员函数。但我们更常用的是 class,因为class 默认是private ,而struct 默认是 public。(这个下面会讲)

既然C++中的 class 是在C的 struct 基础上进行升级的,那么定义方式自然也和C中的 struct 类似。

cpp 复制代码
//定义一个类
class classname    // classname为类名
{
// 类的成员
public:
    void func()
    {
        cout << "成员函数" << endl;
    }
private:
    char* _c = "成员变量";
};
  • 首先,定义类要用class关键字,后面跟着的就是类名
  • 我们发现,类的成员中除了有成员变量 ,还有成员函数 。成员变量也叫类的属性 ,成员函数也叫做类的方法
  • 为了区分成员变量和成员函数的参数,我们通常会在成员变量命名时前面加上一个 _m_,表示 member
  • 类中的成员函数默认时 inline 内联函数
  • 也可以用 struct 去定义一个类,它与 class 的区别就是,一个默认为 private,一个默认为 public

那么说了半天,到底privatepublic是什么?

访问限定符

我们通过名字也能大概猜出这个符号的作用了,那就是去限制外部访问成员的权限 。我们通过访问限定符,可以选择性地将接口提供给外部。

  • 实现封装:隐藏内部实现细节,只暴露必要接口

  • 保护数据:防止外部随意修改,可在成员函数中加入检查逻辑

三种访问限定符:

  • public:修饰的成员可以在类外直接访问
  • private/protect :修饰的成员不能在类外访问。private 和 protect 还有一些不同,这里我们先不提,在后面学习继承 时会细说,这里我们只需要知道他们都表示私有就可以了。

一般的成员变量 都会被限制为private,防止外部随意访问。

我们在C语言中,只能简陋地将数据放在struct中,再另外实现一堆方法,这样程序员可以随意访问数据,随意调用函数。而在C++当中有了访问限定符 ,我们的对象也更加安全、完善

类域

类定义了一个新的作用域,类内部的成员只能在类内访问,类外部访问必须通过对象作用域限定符::

比如我们在类外定义成员函数:

cpp 复制代码
class Person {
public:
    void Show();   // 声明
private:
    string _name;
};

// 类外定义需要加 Person::
void Person::Show() {
    cout << _name << endl;  // 仍能访问私有成员,因为处于类域中
}

注:类域不影响生命周期

实例化

  • 类的定义实际上只是定义了一种数据类型,它本身是没有大小的,与内置类型 int、char 一样。

  • 对象是类的一个具体实例,占用实际内存。对象与我们用内置类型创建出的变量一样。

  • 我们用类这个类型,创建出一个具体的实例对象的过程,就叫实例化对象

对象的大小

  • 类实例化出的对象在计算大小时也遵循内存对齐规则 (忘记的同学回看我们C语言结构体那一篇文章)
  • 由于成员函数都是相同的,因此在存储时只会存储成员变量不会存储成员函数
  • 如果一个对象没有成员变量,只有成员函数,那么默认分配一个字节用于占位

到这里,就产生了一个问题:如果每个对象都不存储成员函数,都调用同一个成员函数,那么如何传递成员变量呢?成员函数是怎么知道被哪个对象调用的呢?

给大家举个例子

cpp 复制代码
class A
{
public:
    void func()
    {
        cout << _a << endl;
    }
private:
    int _a;
}

int main()
{
    A a1;
    A a2;
    
    a1.func();
}

这里我们用 A 实例化两个对象 a1,a2 ,然后调用 func 成员函数,那么此时 func 函数是怎么知道自己是被a1调用还是被a2调用的呢?

这时候应该会有很多人注意到我们func函数前面的a1. ,没错,确实由于前面加上了 a1. 之后 func 才知道自己被谁调用了。那么 func 函数中的 _a成员是怎么传递进去的?

这里就引出了我们下面要说的 this 指针

this 指针

在我们调用成员函数时,编译器 会在第一个参数的位置为我们加上一个形参,this指针 ,类型为当前类类型

cpp 复制代码
a1.func(A* const this);

这是上面的函数调用被编译器处理之后的样子,我们的this指针 其实就相当于 &a1 , 函数内部的 _a 实际上就变为了 this->_a,这样就确保了函数中的成员变量就是调用成员函数对象的成员变量。

同时我们注意到 this 指针是被 const 修饰 的,因此不能修改

那么这个 this 指针我们能不能用呢?可以的。

  • C++规定,不能在实参和形参显式地写 this 指针,但可以在函数内部显式地使用 this 指针

意思就是,这个 this 指针不需要我们在参数的位置写上,编译器会自动帮我们加上,我们在函数内部可以直接使用这个 this 指针。

下面我们来看一道题

cpp 复制代码
class A
{
public:
    void Print()
    {
        cout << "A" << endl;
    }
private:
    int _a;
}
int main()
{
    A* p = nullptr;
    p->Print();
}

这个程序能否正常运行?思考一下

答案是可以正常运行。

前面我们说过,对象不会存储成员函数,成员函数单独存储,然后用传入的 this 指针区分是哪个对象调用的。因此这个函数调用实际是这样的

cpp 复制代码
Print(A* const this);

这里的 this 指针就是 p,他们的值为 nullptr,所以程序能不能正常运行取决于this指针在函数内部 有没有被解引用 。成员函数的调用过程 实际上是不涉及对 p 的解引用的。

本篇内容至此也就结束了,但对于类和对象来说,这仅仅只是一小步。

相关推荐
yongui478341 小时前
基于稀疏低秩分解的图像去噪MATLAB实现
开发语言·matlab
誰能久伴不乏1 小时前
工业级 Modbus 上位机架构:基于滴答引擎与状态锁的高并发调度器
c++·qt·架构
geovindu1 小时前
python: N-Barrier Pattern
开发语言·python·设计模式·屏障模式
战族狼魂1 小时前
MetaPrompt编译器核心逻辑拆解
开发语言·人工智能·python
gihigo19981 小时前
MATLAB实现光谱特征波长提取
开发语言·matlab
代钦塔拉1 小时前
Qt信号槽参数类型全解:原生类型、结构体、enum class强枚举注册与传参实战
开发语言·qt
谷谷地图下载器1 小时前
全球、台湾省的无水印·街景数据(离线数据),专为可视化项目定制,支持国产化
javascript·c++·3d·arcgis·sqlite
dinl_vin1 小时前
Python 并发编程实战:多线程、协程与多进程全解析
开发语言·人工智能·python
程序大视界1 小时前
【C++ 从基础到项目实战】C++(五):类与对象基础——构造、析构与访问控制
开发语言·c++·cpp