初始类与对象

初始类与对象

实验介绍

本课程是进一步对类与对象的深入认识,如何定义并实例化一个类,介绍如何使用 C++ 标准库 string 类等。

知识点
  • 认识类与对象
  • 内联函数
  • string
  • 类的定义与实例化

认识类与对象

官方定义

类:在面向对象编程中是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法。

对象:通过类创建出对象,又称实例化对象。

深入理解类

类是 C++ 的核心特性,在 C++ 的世界中,可以将所有事物都看作为一个对象,将对象进行封装之后成为一个类,通常被称为用户定义类型。

例如:可以将猫、狗、鸟、桌子、学生、人、三角形、矩形等都封装为一个类,只要在实际编程中用到的都可以抽象封装为一个类。

C++ 相关概念
概念描述
构造函数类的构造函数是一种特殊的函数,在创建一个新的对象时自动调用
析构函数类的析构函数也是一种特殊的函数,在删除所创建的对象时自动调用
拷贝构造函数拷贝构造函数,是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象
友元函数友元函数可以访问类的 privateprotected 成员
内联函数通过内联函数,编译器试图在调用函数的地方扩展函数体中的代码
类成员函数类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样
类访问修饰符类成员可以被定义为 publicprivateprotected。默认情况下是定义为 private
this 指针每个对象都有一个特殊的指针 this,它指向对象本身
静态成员类的数据成员和成员函数都可以被声明为静态的

自定义类

假设最近在做一个学校管理系统的项目,首先想到可以将学生定义为一个类,然后发现可以在学生类的基础上再抽象出一个人类的对象,如果需要用到学生的学科,可以进一步将学科也封装为一个,还可以封装文件操作类,数据库操作类等等。

示例代码 1

定义一个学生类:

#include <iostream>
#include <string>
using namespace std;

// class 类关键字、Student 类名
class Student
{
// 访问限制符 - 公有属性
public:
    Student() {}    // 构造函数
    ~Student() {}    // 析构函数

    // 成员函数
    void setName(string name) { this->name = name; }
    string getName() const { return name; };
    void setAge(int age) { this->age = age; }
    int getAge() const { return age; }
// 访问限制符 - 私有属性
private:
    // 数据成员
    string name;
    int age;
};

类定义注意事项:

  1. 定义一个类时,需要使用关键字 class 来进行修饰。
  2. 一个简单的类可以没有构造函数和析构函数,但是系统自动生成一个默认的构造函数和析构函数。
  3. 在类中使用关键字 publicprivateprotected 来限制数据成员和成员函数,一般使用 publicprivate 来修饰数据成员和成员函数。
  4. 一般将数据成员封装在 private 关键字下,不让用户直接访问数据成员,而是通过成员函数来进行访问。
  5. 在类的最后(大括号后)必须要有一个分号,勿忘。

实例化对象

实例化对象有两种方式,一种是在栈上实例化,另一种是在堆上实例化。

示例代码 2
int main()
{
    // 栈上实例化
    Student stu1;
    stu1.setName("jake");
    stu1.setAge(15);
    cout << "My name is " << stu1.getName() << ", I'm " << stu1.getAge() << " years old." << endl;

    // 堆上实例化
    Student *stu2 = new Student;
    // 访问
    stu2->setName("Siri");
    stu2->setAge(5);
    cout << "My name is " << stu2->getName() << ", I'm " << stu2->getAge() << " years old." << endl;
    // 释放内存
    delete stu2;
    stu2 = nullptr;

    return 0;
}

实例化对象注意事项:

  1. 在栈上实例化的对象,超出定义域对象资源会自动被系统回收。
  2. 在堆上实例化的对象,最后需要使用 delete 关键字来释放内存,否则会造成内存泄漏。
  3. 使用栈实例化的对象使用 “.” 来访问数据成员或成员函数,在堆上实例化的对象使用 “->” 来访问数据成员或成员函数。
  4. 释放完内存后将对象置空,防止野指针。

string 类

C++ 标准库:前人开发时编写的类,并被收录成为通用的标准类,之后的人开发时可以直接使用,避免重复造轮子。string 类是开发时经常会使用到的一个类。

string 类是 C++ 标准库中的字符串类,专用于字符串操作,接下来介绍一下如何使用 string 类。

string 介绍

  1. string 类头文件 #include<string>
  2. string 类在 std 命名空间内。
  3. 使用 string 实例化一个字符串类型的对象。
  4. 对字符串对象执行例如拼接、查找等操作。
string 初始化方式
实例化解释
string s1;s1 为空字符串
string s2(“ABC”);s2 初始值为 “ABC”
string s3 = s2;
string s3(s2);s3 初始化为 s2 的一个副本
string s4(n, ‘c’ );s4 初始化为字符 ‘c’ 的 n 个副本
string 常用操作

以下列出了 string 经常使用的操作,如果还需要用到其他操作可以在 官网 查找 string 类的相关使用方法,里面配有示例程序。

操作解释
s.empty()判断 s 是否为空,如果 s 为空返回 true,否则返回 false
s.size()返回 s 中字符的个数,和 s.length() 功能相同
s[n]返回 s 中位置 n 的字符,位置从 0 开始。切记不要越界
s1 + s2将 s1 和 s2 连接成新字符串,返回新字符串
s1 = s2赋值,将 s2 内容赋值给 s1
s1 == s2判断相等,相等返回 true,否则返回 false
s1 != s2判断不等,不等返回 true,否则返回 false
s.c_str()返回 char*,和 s.data() 功能相同
stoi()字符串转 int,还有 stol(),stoll()
stof()字符串转 float, 还有 stod(),stold()
示例代码 3

string 类提供丰富的初始化方式,但也需要注意示例中错误的初始化方式。

// string 初始化
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s1;
    string s2 = "hello";
    string s3("world");
    string s4 = s1 + s2;
    string s5 = "hello " + s2;
    string s6 = "hello " + s2 + "world";
    string s7(5, 'c');
    string s8 = "hello" + " world"; // Error

    return 0;
}

示例代码 4

string 类在实际开发中经常使用,功能也是相当的强大,下面通过示例代码来体验一下。

#include <iostream>
#include <string>
using namespace std;

int main()
{
    // 初始化
    string s1 = "hello";
    string s2 = "this is shiyanlou.";

    // size() 和 length() 都是返回字符串的长度
    cout << "s1.size() = " << s1.size() << endl;
    cout << "s1.length() = " << s1.length() << endl;

    // 需要注意 capacity() 是返回 string 的当前容量,string 本身是一个数组,所以 capacity() 返回的长度可能会大于 size() 或者 length() 返回的长度
    cout << "s1.capacity() = " << s1.capacity() << endl;

    // s1.at(i) 和 s1[i] 都是访问位置 i 的字符
    cout << "s1.at(1) = " << s1.at(1) << endl;
    cout << "s1[1] = " << s1[1] << endl;

    // find() 查到字符,找到返回字符串位置,否则返回 -1
    cout << "s1.find('e') = " << s1.find('e') << endl;
    // 指定起始位置查到
    cout << "s2.find(\"is\", 4) = " << s2.find("is", 4) << endl;
    // 逆序查找
    cout << "s2.rfind(\"is\") = " << s2.rfind("is") << endl;

    // 判断字符串是否为空
    if (s1.empty()) {
        cout << "s1 is empty." << endl;
    }
    else {
        cout << "s1 is not empty." << endl;
    }

    // 判断字符串是否相等
    if (s1 == "hello") {
        cout << "s1 == hello" << endl;
    }
    else {
        cout << "s1 != hello" << endl;
    }

    // string --> int
    string s3 = "1314";
    cout << "stoi(s3) = " << stoi(s3) << endl;
    // string --> float
    string s4 = "3.1415";
    cout << "stof(s4) = " << stof(s4) << endl;
    return 0;
}

内联函数

官方定义:内联函数又是称作 “在线函数” 或者 “编译时期展开函数” 的一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展;也就是说建议编译器将制定的函数体插入并取代每一次调用该函数的地方,从而节省每次调用函数带来的额外时间开支。

  1. 定义内联函数关键字:inline
  2. 内联分为普通内联函数和类内联函数。
  3. 定义内联函数时一般使用于简单的函数,如果函数比较复杂,编译器也将自动取消内联。
普通内联函数 - 示例代码 5
#include <iostream>
using namespace std;

int max(int a, int b)
{
    return a > b ? a : b;
}

inline int min(int a, int b)
{
    return a > b ? b : a;
}

int main()
{
    int a = 5, b = 7;
    // 普通函数求最大值
    cout << "max(a, b) = " << max(a, b) << endl;

    // 内联函数求最小值
    cout << "min(a, b) = " << min(a, b) << endl;

    return 0;
}

编译过程

类内联函数

如下图是使用类内定义一个类的方法(“类的定义域实例化” 小节中会讲到类内定义),而使用类内定义的成员函数编译器会默认将成员函数当做为内联函数进行编译。但如果成员函数比较复杂,编译器也不会将成员函数当做内联函数进行编译。

小结
  1. 编译器在编译时会将内联函数直接插入到调用内联函数处,这样可以减去调用函数时的开销。
  2. 在实际开发过程中,可以酌情考虑使用类内定义的方法实现类成员函数。

类的定义与实例化

在学习本小节之前先来学习另外两个知识点。

  • 类内定义。
  • 类外定义。
  • 同文件类外定义。
  • 分文件类外定义。

在实际开发过程中需要考虑到程序的架构问题,类内定义适用于一个相对比较简单的程序,考虑到开发时的方便性和时间成本,类外定义是实际程序开发中常用的方法。

类内定义

类内定义即在类中实现成员函数。

示例代码 6
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
    Student() {}
    ~Student() {}
    // 定义成员函数并实现功能
    void setName(string name) { this->name = name; }
    string getName() const { return name; };
    void setAge(int age) { this->age = age; }
    int getAge() const { return age; }
private:
    string name;
    int age;
};

int main()
{
    Student stu;
    stu.setName("jake");
    stu.setAge(15);
    cout << "My name is " << stu.getName() << ", I'm " << stu.getAge() << " years old." << endl;

    return 0;
}

小结

在以上示例代码中,类中定义的成员函数都是使用的类内定义的方式实现的,在实际的开发中不建议这样做,除非是定义一个非常简单的类或者成员函数。

在内联函数小节中提到过,类内定义的方式编译器会自动尝试将成员函数作为内联函数进行编译,如果成员函数比较复杂,编译器将不会作为内联函数进行编译。

类外定义

类外定义有两种方式:

  1. 同文件类外定义。
  2. 分文件类外定义。
同文件类外定义 - 示例代码 7
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
    Student();
    ~Student();
    void setName(string name);
    string getName() const;
    void setAge(int age);
    int getAge() const;
private:
    string name;
    int age;
};

Student::Student()
{
}

Student::~Student()
{
}

void Student::setName(string name)
{
    this->name = name;
}

string Student::getName() const
{
    return name;
};


void Student::setAge(int age)
{
    this->age = age;
}

int Student::getAge() const
{
    return age;
}


int main()
{
    Student stu;
    stu.setName("jake");
    stu.setAge(15);
    cout << "My name is " << stu.getName() << ", I'm " << stu.getAge() << " years old." << endl;

    return 0;
}

分文件类外定义 - 示例代码 8
// Student.h 文件
#ifndef __STUDENT__
#define __STUDENT__
#include <iostream>
#include <string>
using namespace std;

class Student
{
public:
    Student();
    ~Student();
    void setName(string name);
    string getName() const;
    void setAge(int age);
    int getAge() const;
private:
    string name;
    int age;
};

#endif // __STUDENT__

// Student.cpp 文件
#include "Student.h"    // 记得添加类头文件

Student::Student()
{
}

Student::~Student()
{
}

void Student::setName(string name)
{
    this->name = name;
}

string Student::getName() const
{
    return name;
};


void Student::setAge(int age)
{
    this->age = age;
}

int Student::getAge() const
{
    return age;
}

// main.cpp 文件
#include <iostream>
#include "Student.h"

int main()
{
    Student stu;
    stu.setName("jake");
    stu.setAge(15);
    cout << "My name is " << stu.getName() << ", I'm " << stu.getAge() << " years old." << endl;
    return 0;
}

文件结构以及运行结果截图:

小结

同文件类外定义就是将类的成员函数定义在类之外的地方,同时类的成员函数使用类作用域来进行定义。在实际项目开发中,类不是很复杂时可以使用该方法,类比较复杂时不推荐使用。

分文件定义类就是将类的定义放在 xxx.h 头文件中,而类的成员函数实现放在 xxx.cpp 文件中。这种做法是做项目时推荐使用的方法,因为这样将类的定义和成员函数分开后,在开发时很容易能够查找到对应的定义和成员函数。

一般情况下文件名和类名相同,便于开发时类管理。

实验总结

知识点总结
  • 深入认识类与对象并讲解 C++ 相关概念。
  • 如何使用 string 类。
  • 普通内联函数与类内联函数以及编译器对内联函数的处理。
  • 学习类内定义与类外定义,开发时常使用分文件类外定义的方法。
  • main 函数的返回值为 int 类型,注意不要写成 void 类型。
章节总结

本章节讲解的是比较基础的知识点,但是在开发中却非常的重要,在接下来的章节中将会越来越深的学习 C++ 知识。

希望在本章节结束后能掌握如何定义和使用类,并且掌握在工作中的实际用法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/226507.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言快速学习基础篇】之一基础类型、进制转换、数据位宽

文章目录 一、基础类型(根据系统不同占用字节数会有变化)1.1、有符号整形1.2、无符号整形1.3、字符型1.4、浮点型1.5、布尔型 二、进制转换2.1、二进制2.2、八进制2.3、十进制2.4、十六进制2.5、N进制2.6、进制转换关系对应表 三、数据位宽3.1、位3.2、字节3.3、字3.4、双字3.5…

Java + Selenium + Appium自动化测试

一、启动测试机或者Android模拟器&#xff08;Genymotion俗称世界上最快的模拟器&#xff0c;可自行百度安装&#xff09; 二、启动Appium&#xff08;Appium环境安装可自行百度&#xff09; 三、安装应用到Genymotion上&#xff0c;如下图我安装一个计算机的小应用&#xff0c…

【android开发-05】android中activity的启动模式介绍

1&#xff0c;活动的启动模式 在 Android 中&#xff0c;Activity 的启动模式主要有以下四种&#xff1a; 默认启动模式&#xff08;Normal&#xff09;&#xff1a;这是默认的启动模式&#xff0c;基本上就是标准的启动模式。当一个 Activity 启动后&#xff0c;它将会被压入…

C51--IIC协议

IIC协议初识&#xff1a; 1、概述 IIC全称Inter-Integrated Circuit (集成电路总线) 是由PHILIPS公司在80年代开发的两线式串行总线&#xff0c;用于连接微控制器及其外围设备。 IIC属于半双工同步通信方式 SCL——时钟信号 SDA——数据信号 2、特点&#xff1a; 简单性和…

堆栈,BSS,DATA,TEXT

一、目标文件 首先目标文件的构成&#xff0c;Linux下就是.o 文件 编译器编译源码后生成的文件叫目标文件&#xff08;Object File&#xff09;。 目标文件和可执行文件一般采用同一种格式&#xff0c;这种存储格式为 ELF。 目前文件的内容至少有编译后的机器指令代码和数据&a…

leetcode 622. 设计循环链表

这道题讲了两种方法&#xff0c;第一个代码是用数组实现的&#xff0c;第二个是用链表实现的&#xff0c;希望对你们有帮助 &#xff08;最好在VS自己测试一遍&#xff0c;再放到 leetcode上哦&#xff09; 下面的是主函数&#xff08;作参考&#xff09;&#xff0c;静下心来…

第二十一章——网络通信

一.网络程序设计基础 1.局域网与互联网 2.网络协议 1.IP协议 IP是Internet Protocol的简称&#xff0c;是一种网络协议。 1.1 TCP/IP层次结构 2.TCP与UDP协议 TCP可保证数据从一端送至另一端时&#xff0c;能够确实送达&#xff0c;而且抵达的数据的排列顺序和送出时的顺序相…

AWR1642 boost开发板支持的TI参考设计

打开radar_toolbox_1_30_00_05\source\ti\examples\examples_overview,通过输入“1642”查找AWR1642 BOOST支持的参考设计,通过筛选,支持AWR1642 BOOST的参考设计如下: 挑选出两个参考设计上手,一个是“nonos_oob_16xx",不带OS;另一个是”short range radar“,比较…

吹响AI技术应用的号角

毫无疑问&#xff0c;各企业正围绕各种技术展开一场持续不断的角逐&#xff0c;力争率先取得领先且具创新性的技术进步&#xff0c;AI技术也不例外。疫情期间&#xff0c;全球各地企业的员工纷纷转向居家办公。因此&#xff0c;为轻松实现这一转型并建立起远程办公的新常态&…

用23种设计模式打造一个cocos creator的游戏框架----(四)装饰器模式

1、模式标准 模式名称&#xff1a;装饰器模式 模式分类&#xff1a;结构型 模式意图&#xff1a;动态地给一个对象添加一些额外的职责。就增加功能来说&#xff0c;装饰器模式比生成子类更为灵活。 结构图&#xff1a; 适用于&#xff1a; 当需要给一个对象在运行时添加更…

使用命令行创建vue3项目等待时间长解决方案

问题描述 今天在使用命令行创建vue3项目的时候&#xff0c;发现命令行窗口卡了很久&#xff0c;明明已经更换了安装包的源&#xff0c;并且检查环境变量配置正确的情况下&#xff0c;为什么还要等待那么久呢&#xff1f; 解决方案 使用命令再次检查更换淘宝的源是否配置成功…

混沌映射初始化种群与随机初始化种群初始种群分布图对比

自行切换混沌映射&#xff0c;代码如下&#xff1a; Lb -1; % 搜索空间下界 Ub 1; % 搜索空间上界N_iter 500; % 最大迭代次数 N 30; % 种群个数 dim 2; % 种群维度 Z zeros(N, dim);% 随机生成一个d维向量 Z(1, :) rand(1, dim);% 利用logistic生成N个向量 for i…

C++新经典模板与泛型编程:用成员函数重载实现std::is_convertible

用成员函数重载实现is_convertible C标准库中提供的可变参类模板std::is_convertible&#xff0c;这个类模板的主要能力是判断能否从某个类型隐式地转换到另一个类型&#xff0c;返回的是一个布尔值true或false。例如&#xff0c;一般的从int转换成float或从float转换成int&am…

锁表的原因及解决办法

引言 作为开发人员&#xff0c;我们经常会和数据库打交道。 当我们对数据库进行修改操作的时候&#xff0c;例如添加字段&#xff0c;更新记录等&#xff0c;没有正确评估该表在这一时刻的使用频率&#xff0c;直接进行修改&#xff0c;致使修改操作长时间无法响应&#xff0…

孩子都能学会的FPGA:第二十四课——用FPGA和格雷码实现异步FIFO

&#xff08;原创声明&#xff1a;该文是作者的原创&#xff0c;面向对象是FPGA入门者&#xff0c;后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门&#xff0c;作者不光让大家知其然&#xff0c;还要让大家知其所以然&#xff01;每个工程作者都搭建了全自动化的仿…

数据结构 图的广度优先搜索和深度优先搜索

一、广度优先搜索 广度优先搜索等价于树的层次遍历&#xff0c;将起点的每一层进行遍历 当这一层结点全部被遍历完时&#xff0c;再遍历下一层次&#xff0c;从图中可以根据距离遍历起点的长度进行层次选择 例&#xff1a; 以a结点作为开始结点 a的下一层次有b c e三个结点 所以…

GIT GUI使用

文章目录 一、新建本地仓库二、推送&#xff08;push&#xff09; 一、新建本地仓库 在空白处右键&#xff0c;找到GIT GUI here&#xff0c; 如果没有仓库&#xff0c;出现的是这样的&#xff1a; 如果有仓库&#xff0c;在本地仓库里打开就是这样的&#xff1a; 新建本地…

Http协议与Tomcat

HTTP协议 HTTP协议&#xff08;HyperText Transfer Protocol&#xff09;即超文本传输协议 &#xff0c;是TCP/IC网络体系结构应用层的一个客户端-服务端协议&#xff0c;是所有客户端&#xff0c;服务端数据传输的基石&#xff08;数据传输规则&#xff09; 特点 ⭐基于TCP协…

C++刷题 -- 链表

C刷题 – 链表 文章目录 C刷题 -- 链表1.删除链表的倒数第 N 个结点2.链表相交3.环形链表 1.删除链表的倒数第 N 个结点 https://leetcode.cn/problems/remove-nth-node-from-end-of-list/ 快慢指针的应用 fast指针先移动N步&#xff0c;slow依然指向head&#xff1b;然后fa…

算法-01-递归

1-理解递归 斐波那契数列&#xff08;Fibonacci sequence&#xff09;&#xff0c;又称黄金分割数列 &#xff0c;以兔子繁殖为例子而引入&#xff0c;故又称“兔子数列”&#xff0c;其数值为&#xff1a;1、1、2、3、5、8、13、21、34……特点是 从第三个数开始&#xff0c;第…