C++零基础教程(C++中的类1)

2023-07-13 09:49:51


前言

本篇文章我们继续来讲解C++中的类。

一、初始化列表

初始化列表是在 C++ 类的构造函数中使用的一种特殊语法。它允许在对象创建时对成员变量进行初始化。

通常,在构造函数的函数体中,我们会使用赋值操作符(=)来对成员变量进行初始化。然而,初始化列表提供了一种在构造函数签名之后的初始化成员变量的方式。

初始化列表使用冒号(:)后跟一个成员初始化列表。每个初始化列表由成员变量名和其对应的初始值构成,并用逗号分隔。

以下是初始化列表的基本语法:

ClassName(constructor_arguments) : member1(initial_value1), member2(initial_value2), ... {
    // 构造函数体
}

例如,考虑以下的示例类 Person,具有 name 和 age 成员变量:

class Person {
    std::string name;
    int age;

public:
    Person(const std::string& personName, int personAge) : name(personName), age(personAge) {
        // 构造函数体
    }
};

在上面的代码中,构造函数使用初始化列表来对 name 和 age 成员变量进行初始化。传递给构造函数的参数 personName 和 personAge 用于初始化列表,并通过冒号分隔。

使用初始化列表的好处有几个:

1.效率:初始化列表允许直接对成员变量进行初始化,而不是采用默认构造函数再赋值的方式。这样可以减少额外的构造和赋值操作,提高效率。

2.对于 const 成员和引用类型成员变量,它们只能通过初始化列表进行初始化。这是因为在构造函数体内无法对 const 成员和引用类型成员变量进行赋值操作。

3.初始化顺序:初始化列表可以用于指定成员变量的初始化顺序。成员变量的初始化顺序与在初始化列表中的顺序相同,而不是与它们在类定义中出现的顺序相同。

二、类中的const成员

在一个类(或结构体)中声明的 const 成员是指成员变量的值在对象创建后不能被修改。这意味着,一旦一个对象被创建并初始化,const 成员的值就不能再改变。

在类的定义中,可以使用 const 关键字来声明 const 成员。例如:

class MyClass {
    const int myConstMember;

public:
    MyClass(int value) : myConstMember(value) {
        // 构造函数中的初始化列表用于初始化const成员
    }
};

在上面的示例中,MyClass 类包含一个 const 成员 myConstMember,它被初始化为通过构造函数传递的值。

const 成员的主要特点是:

1.它们必须在构造函数的初始化列表中进行初始化。一旦初始化,就不能在类的其他成员函数中修改它们的值。

2.const 成员不能被修改,即不能被赋新值。任何修改 const 成员的尝试都会导致编译错误。

3.const 成员的值对于每个对象而言是唯一的,而不是共享的。每个对象都有自己的 const 成员副本。

MyClass obj1(10);
MyClass obj2(20);

obj1.myConstMember = 5;  // 错误,无法修改const成员的值
obj2.myConstMember++;    // 错误,无法修改const成员的值

const 成员通常用于表示对象的不可变属性,例如对象的常量配置,或者在类中提供只读的状态信息。

需要注意的是,const 成员的初始化只能在构造函数中进行,而不能在类体外部初始化,并且每个对象的 const 成员的值可以是不同的,取决于构造函数中传递的值。

三、析构函数

在C++中,析构函数(Destructor)是一种特殊的成员函数,它在对象被销毁时自动调用。析构函数的主要目的是进行资源的释放和清理操作。

析构函数的命名规则与类名相同,但在类名前加上波浪号(~)。它没有任何参数,也没有返回类型。一个类可以有一个析构函数,用于清理对象的资源,释放它所占用的内存或关闭打开的文件等。

以下是析构函数的基本语法:

class ClassName {
public:
    // 构造函数和其他成员函数

    ~ClassName() {
        // 析构函数的实现
    }
};

当对象的生命周期结束时,例如在以下情况下,析构函数会自动调用:

当对象被定义为自动变量,超出其作用域时。
当对象是动态分配的,通过 new 运算符创建,然后通过 delete 运算符释放它时。
当对象是类的成员,而其所属的类对象被销毁时,会自动调用成员对象的析构函数。

析构函数可以用于执行以下操作:

执行资源的释放,例如关闭文件、释放内存、释放网络连接等。

清理对象内部可能存在的动态分配的资源,以防止内存泄漏。

执行其他必要的清理操作以保证对象的数据和状态的一致性。

需要注意的是,如果类没有显式定义析构函数,编译器会自动生成默认的析构函数。默认析构函数执行对象的销毁操作,但不会进行任何特定的资源释放或清理操作。

析构函数的执行顺序与构造函数相反。析构函数首先调用派生类的析构函数,然后调用成员对象的析构函数,最后调用基类的析构函数。

在设计类时,若类需要管理动态分配的资源或进行其他特定的清理操作,通常需要显式定义析构函数。这确保了在对象销毁时进行必要的资源释放和清理。

四、临时对象

临时对象(Temporary objects)是在表达式求值过程中临时创建的对象,用于保存中间结果或执行特定的操作。它们没有命名,并且通常在同一行代码中即时创建和销毁。

临时对象可以出现在各种情况下,例如函数返回值、函数参数传递、运算符重载等。下面让我详细解释一些常见情况下的临时对象:

1.函数返回值:函数可以返回一个临时对象作为其返回值。例如:

class Point {
    int x, y;

public:
    Point(int xPos, int yPos) : x(xPos), y(yPos) {}

    Point operator+(const Point& other) const {
        return Point(x + other.x, y + other.y);
    }
};

Point addPoints(const Point& p1, const Point& p2) {
    return p1 + p2;  // 返回临时对象
}

在上面的示例中,addPoints 函数返回一个 Point 类型的临时对象作为两个输入点的和。

2.函数参数传递:临时对象也可以作为函数参数传递给其他函数。例如:

void printPoint(const Point& point) {
    // 打印点的坐标
}

int main() {
    printPoint(Point(3, 4));  // 传递临时对象作为参数
    return 0;
}

在这个例子中,Point(3, 4) 创建了一个临时对象,并将其作为参数传递给 printPoint 函数。

3.运算符重载:通过运算符重载,可以为类定义各种运算操作,并创建临时对象作为结果。例如:

class Integer {
    int value;

public:
    Integer(int val) : value(val) {}

    Integer operator+(const Integer& other) const {
        return Integer(value + other.value);  // 返回临时对象
    }
};

int main() {
    Integer a(5);
    Integer b(10);
    Integer c = a + b;  // 创建临时对象作为结果
    return 0;
}

在这个例子中,a + b 运算创建了一个临时对象,表示 a 和 b 相加的结果。

临时对象的生命周期通常很短暂,它们在使用后会立即销毁。它们的创建和销毁是由编译器自动处理的,无需手动管理。

临时对象的使用可以提高代码的简洁性和可读性,但需要注意的是,在使用临时对象时,确保不会出现不必要的复制操作或资源泄漏。

总结

更多推荐

nginx配置指南

nginx.conf配置找到Nginx的安装目录下的nginx.conf文件,该文件负责Nginx的基础功能配置。配置文件概述Nginx的主配置文件(conf/nginx.conf)按以下结构组织:配置块功能描述全局块与Nginx运行相关的全局设置events块与网络连接有关的设置http块代理、缓存、日志、虚拟主机等

RISV-V架构的寄存器介绍

1、RISC-V的通用寄存器(1)在编写汇编代码时,使用寄存器的ABI名字,一般不直接使用寄存器的编号;(2)x0-x31是用来做整形运算的寄存器,f0-f31是用来做浮点数运算的寄存器;RISC-V一定有x0-x31寄存器,但是不一定有f0-f31寄存器,这要看支不支持浮点数运算;(3)保存者:调用者保存就是在函数跳

关系型数据库和非关系型数据库

关系型数据库和非关系型数据库关系型数据库非关系型数据库非关系型数据库和关系型数据库是两种不同类型的数据库管理系统,它们用于存储和管理数据,但在数据组织和处理方式上有一些重要的区别。关系型数据库1.结构化数据存储:关系型数据库以表格形式存储数据,数据以行和列的方式组织,每个表都有预定义的模式(也称为模式或架构),这意味着

Hive参数与性能调优-V2.0

Hive作为大数据平台举足轻重的框架,以其稳定性和简单易用性也成为当前构建企业级数据仓库时使用最多的框架之一。但是如果我们只局限于会使用Hive,而不考虑性能问题,就难搭建出一个完美的数仓,所以Hive性能调优是我们大数据从业者必须掌握的技能。本文将给大家讲解Hive性能调优的一些方法及技巧。一、Hive性能调优的方式

论文阅读之Learning and Generalization of Motor Skills by Learning from Demonstration

论文阅读其实就是用自己的话讲一遍,然后理解其中的方法0、论文基本信息为什么阅读此篇论文:因为它是DMP经典论文,被引多次,学史可以明智,了解最初机理。论文题目:LearningandGeneralizationofMotorSkillsbyLearningfromDemonstration会议名称:2009ICRA论文

Zookeeper集群 + Kafka集群

Zookeeper概述Zookeeper定义Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。Zookeeper工作机制Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变

《计算机视觉中的多视图几何》笔记(1)

1Introduction–aTourofMultipleViewGeometry本章介绍了本书的主要思想。1.1Introduction–theubiquitousprojectivegeometry为了了解为什么我们需要射影几何,我们从熟悉的欧几里得几何开始。欧几里得几何在二维中认为平行线是不会相交的,解决这个问题

【Linux网络编程】日志与守护进程

日志是网络服务器程序在后台以守护进程的形式运行时,处理情况的描述被打印到了日志文件里面,方便维护人员查看。1.前台进程与后台进程左边会话输入命令sleep10000&代表进程后台运行,右边会话输入命令sleep20000可以看到命令行解释器直接卡住了。STATS+就是前台进程的意思,STATS就是后台进程。可以看到后台

自动化控制系统的设计重点是什么?

要实现对选择性激光烧结系统预热温度的控制,需要找到合理的控制对象模型,但选择性激光烧结设备的预热温度场是一个复杂的非线性系统,很难找到合理的控制对象模型来实现预热温度场的温度控制。模糊控制不需要具体的控制模型,预热温度场的温度控制只能通过模糊推理来实现。模糊控制技术是现代控制理论中基于语言规则和模糊推理的先进控制策略和

狂神docker

狂神说docker参考文章-----docker概述docker为什么会出现?–环境部署麻烦,两套环境(开发-运维)我的电脑可以运行,到你那就不可用。开发即运维–开发打包部署上线一条龙环境配置十分麻烦,机器部署耗时间(redis,eshadoop费时费力)发布项目时,带上环境—引出docker–开发打包部署上线,一套流

ETL增量抽取模式实践与调优

在ETL(Extract,Transform,Load)流程中,增量抽取是一种重要的数据提取方式,允许从源系统中仅提取发生变化的数据,以提高处理效率和减少资源消耗。增量抽取模式有多种实现方式,包括时间戳增量、增量标记和增量查询。本文以ETLCloud为例,对这三种增量抽取模式进行深入研究,探讨它们的实践应用、调优技巧和

热文推荐