C++:类和对象(一)

ops/2025/4/1 3:00:55/

目录

函数重载

函数重载的注意事项

缺省参数

缺省参数的规则

引用

引用的基本概念

引用与指针的区别

引用的主要用途

1. 函数参数传递(按引用传递)

2. 避免对象拷贝

3. 函数返回值

常量引用

引用使用的注意事项

1.1 什么是类?

1.2 类与结构体的区别

1.3 访问控制

类的静态成员

this指针

成员函数

构造函数

析构函数

运算符重载


函数重载

函数重载允许我们在同一作用域内定义多个同名函数,只要它们的参数列表不同即可。编译器会根据调用时提供的参数类型和数量来决定调用哪个版本的函数。

参数类型不同:

#include <iostream>
#include <string>// 打印整数的函数
void print(int value) {std::cout << "整数: " << value << std::endl;
}// 打印浮点数的函数
void print(double value) {std::cout << "浮点数: " << value << std::endl;
}// 打印字符串的函数
void print(const std::string& value) {std::cout << "字符串: " << value << std::endl;
}int main() {print(42);          // 调用print(int)print(3.14159);     // 调用print(double)print("Hello");     // 调用print(const std::string&)return 0;
}

参数数量不同:

void fun()
{cout << "fun()" << endl;
}void fun(int a)
{cout << "fun(int a)" << endl;
}

函数重载的注意事项

  1. 仅返回类型不同不构成重载

  2. 参数类型或数量必须不同

  3. 重载解析发生在编译时

  4. 注意避免重载导致的二义性

缺省参数

缺省参数允许函数在定义时为参数指定默认值。如果调用函数时没有提供该参数的值,就会使用默认值。

缺省参数分为全缺省和半缺省。

缺省参数的规则

  1. 缺省参数必须从右向左连续设置

  2. 通常在函数声明中指定缺省参数(而非定义)

  3. 每个缺省参数只能指定一次(通常在头文件中)

  4. 缺省值可以是全局变量、常量或函数调用

引用

引用的基本概念

引用本质上是一个变量的别名,它为已存在的变量提供了另一个名称。在C++中,我们使用&符号来声明引用:

int original = 42;
int& ref = original;  // ref是original的引用

引用与指针的区别

虽然引用和指针在某些方面相似,但它们有几个关键区别:

  1. 初始化要求:引用必须在声明时初始化,而指针可以不初始化(尽管不推荐)。

  2. 可修改性:引用一旦初始化就不能改变指向,指针可以。

  3. 空值:引用不能为NULL或nullptr,指针可以。

  4. 语法:引用使用起来像普通变量,指针需要解引用操作。

int x = 10;
int y = 20;// 指针
int* p = &x;
p = &y;  // 可以改变指向// 引用
int& r = x;
// r = y;  // 这不会改变r的引用,而是把y的值赋给x

引用的主要用途

1. 函数参数传递(按引用传递)

引用最常见的用途是在函数参数传递中,允许函数修改调用者的变量:

void swap(int& a, int& b) {int temp = a;a = b;b = temp;
}int main() {int x = 5, y = 10;swap(x, y);  // x和y的值被交换
}
2. 避免对象拷贝

对于大型对象,按值传递会导致昂贵的拷贝操作。使用引用可以避免这种开销:

void processLargeObject(const LargeObject& obj) {// 不会拷贝LargeObject,同时保证obj不会被修改
}
3. 函数返回值

函数可以返回引用,但必须确保返回的引用指向的对象在函数返回后仍然存在:

int& getElement(std::vector<int>& arr, size_t index) {return arr[index];
}int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};getElement(numbers, 2) = 10;  // 修改numbers[2]为10
}

常量引用

常量引用(const T&)允许我们传递参数而不允许修改它们,同时避免拷贝:

void printString(const std::string& str) {std::cout << str;// str不能被修改
}

引用使用的注意事项

  1. 不要返回局部变量的引用:局部变量在函数结束后会被销毁,返回它们的引用会导致未定义行为。

  2. 引用不是对象:不能创建引用的数组、指向引用的指针或引用的引用(除非使用类型别名)。

  3. 接口设计:当函数需要修改参数时使用非常量引用,否则使用常量引用。

1.1 什么是类?

类(Class)是C++中实现面向对象编程的基本单元,它是用户自定义的数据类型,包含数据成员和成员函数:

class Rectangle {
private:double width;   // 数据成员double height;public:// 成员函数void setDimensions(double w, double h) {width = w;height = h;}double area() const {return width * height;}
};

1.2 类与结构体的区别

在C++中,classstruct非常相似,主要区别在于默认访问权限:

  • class:默认成员是private

  • struct:默认成员是public

class MyClass {     // 默认privateint x;          // private
};struct MyStruct {    // 默认publicint x;          // public
};

1.3 访问控制

C++提供三种访问修饰符:

  1. public:在任何地方都可以访问

  2. private:只能在类内部访问

  3. protected:类内部和派生类中可以访问

class AccessExample {
public:int publicVar;      // 任何代码可访问private:int privateVar;     // 仅类成员函数可访问protected:int protectedVar;   // 类成员和派生类可访问
};

类的静态成员

静态成员属于类本身而非类的实例:

class Counter {
private:static int count;   // 静态数据成员声明public:Counter() { ++count; }~Counter() { --count; }static int getCount() { return count; }  // 静态成员函数
};int Counter::count = 0;  // 静态数据成员定义

this指针


1、this指针在栈区,成员函数有一个隐式形参 类名*const this   只能在成员函数内部使用。

2、this 指针本质上是 “ 成员函数 ” 的形参 ,当对象调用成员函数时,将对象地址作为实参传递给
this 形参。所以 对象中不存储this指针 。
3、  this 指针是 “ 成员函数 ” 第一个隐含的指针形参,一般情况由编译器通过 ecx 寄存器自动传
递,不需要用户传递。

编译器编译后,类的成员函数默认都会在形参第一个位置,增加一个当前类类型的指针,叫做this
指针。比如Date类的Init的真实原型为, void Init(Date* const this, int year, int month, int day)
• 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, this-
>_year = year;
• C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针。

#include<iostream>
using namespace std;
class Date
{
public:
// void Init(Date* const this, int year, int month, int day)void Init(int year, int month, int day){// 编译报错:error C2106: “=”: 左操作数必须为左值// this = nullptr;// this->_year = year;_year = year;this->_month = month;this->_day = day;}
void Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}
private:// 这里只是声明,没有开空间int _year;int _month;int _day;
};int main()
{// Date类实例化出对象d1和d2Date d1;Date d2;// d1.Init(&d1, 2024, 3, 31);d1.Init(2024, 3, 31);d1.Print();d2.Init(2024, 7, 5);d2.Print();return 0;
}

成员函数

C++类有6个特殊成员函数,编译器会在需要时自动生成:

  1. 默认构造函数

  2. 析构函数

  3. 拷贝构造函数

  4. 拷贝赋值运算符

  5. 移动构造函数(C++11)

  6. 移动赋值运算符(C++11)

构造函数

构造函数(一般写成全缺省的)是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。

构造函数的主要任务并不是创建对象,而是初始化对象。

特征如下:

  1. 函数名与类名相同
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载
class Date
{
public:Date(int year = 1, int month = 1, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{Date d1();Date d2(2025, 3, 19);Date d3(2024, 3);return 0;
}

默认生成构造函数:对内置类型成员不做初始化(因此我们要自己写构造函数)。自定义类型成员(class和struct)可以自动调用默认构造函数(它自己的构造函数)。

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意,无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。

析构函数

析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,比如局部对象是存在栈帧的,函数结束栈帧销毁,他就释放了,不需要我们管,C++ 规定对象在销毁时会自动调用析构函数,完成对象中的资源的清理释放工作。

析构函数的特点:

  1. 析构函数名是在类名前加上字符~
  2. 无参数无返回值(也不需要加void)
  3. 一个类只能有一个析构函数。若未显示定义,系统会自动生成默认的析构函数。
  4. 对象生命周期结束时,系统会自动调用析构函数
  5. 跟构造函数类似,我们不写编译器自动生成的析构函数对内置类型不做处理,自定义类型成员会调用它的析构函数
  6. 要注意的是,我们显示写析构函数,对于自定义类型成员也会调用它的析构函数,也就是说自定义类型成员无论什么情况都会自动调用析构函数。
  7. 一个局部域的多个对象,C++规定后定义的先析构。

运算符重载

运算符重载是具有特殊名字的函数,他的名字是有operator和后面要定义的运算符共同构成。和其他函数一样,它也具有其返回类型和参数列表以及函数体。

重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。 

如果一个重载运算符函数是成员函数,则它的第一个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算对象少一个。

运算符重载以后,其优先级和结合性与对应的内置类型运算符保持一致。

//判断两个日期是否相等
class Date
{ 
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool operator==(const Date& d){return _year == d._year&& _month == d._month&& _day == d._day;}private:int _year;int _month;int _day;};


http://www.ppmy.cn/ops/169946.html

相关文章

栈资源释放示例

import java.util.EmptyStackException; /** * 栈资源释放示例类 * 栈资源在编程中通常指两种概念&#xff1a;1) 内存中的调用栈空间&#xff08;存储方法调用和局部变量&#xff09;&#xff0c;由系统自动管理 * 2) 自定义的栈数据结构&#xff08;如链表实现的栈对象&…

基于web的家政服务网站

内容摘要 由于互联网的使用&#xff0c;人们在管理、应用、服务等领域使用数据更加简洁、方便&#xff0c;大大提高了工作效率。互联网正逐渐融入我们的生活&#xff0c;影响和改变我们的生活。 家政服务管理系统是典型的信息管理系统&#xff08;MIS&#xff09;。其开发主要…

6.3 模拟专题:LeetCode 6. Z 字形变换

1. 题目链接 LeetCode 6. Zigzag Conversion 2. 题目描述 将一个给定字符串 s 按照指定的行数 numRows 进行 Z 字形排列后&#xff0c;逐行读取并返回新的字符串。 示例&#xff1a; 输入&#xff1a;s "PAYPALISHIRING", numRows 3 → 输出&#xff1a;"P…

模数转换电路(A/D转换器)

A/D转换&#xff0c;是将输入的模拟电压量转换成相应的数字量。 A/D转换器的类型很多&#xff0c;按工作原理可分为直接转换型和间接转换型两大类。前者直接将模拟电压量转换成数字量&#xff0c;后者是先将模拟电压量转换成一个中间量&#xff0c;再将中间量转换成数字量。 …

Excel第41套全国人口普查

2. 导入网页中的表格&#xff1a;数据-现有链接-考生文件夹&#xff1a;网页-找到表格-点击→变为√-导入删除外部链接关系&#xff1a;数据-点击链接-选中连接-删除-确定&#xff08;套用表格格式-也会是删除外部链接&#xff09;数值缩小10000倍&#xff08;除以10000即可&am…

STM32F103_LL库+寄存器学习笔记02 - 开启SysTick(滴答定时器)中断

导言 《STM32F103_LL库寄存器学习笔记01 - 梳理CubeMX生成的LL库最小的裸机系统框架》上一章节对CubeMX生成的最小系统框架进行梳理&#xff0c;在此工程的基础上&#xff0c;梳理SysTick&#xff08;滴答定时器&#xff09;中断是怎样开启的&#xff1f;为什么SysTick中断会自…

spring 设置接收json request 返回json类型response

在 Spring 中配置接收 JSON 输入并返回 JSON 输出&#xff0c;可以按照以下步骤进行&#xff1a; 1. 添加依赖&#xff08;非 Spring Boot 项目&#xff09; 如果使用 Spring Boot&#xff0c;默认已集成 Jackson&#xff0c;无需额外配置。若为传统 Spring MVC 项目&#xf…

【Excel使用技巧】某列保留固定字段或内容

目录 ✅ 方法一&#xff1a;使用 Excel 公式提取 body 部分 &#x1f50d; 解释&#xff1a; ✅ 方法二&#xff1a;批量处理整列数据 &#x1f6a8; 注意事项 &#x1f6a8; 处理效果 我想保留Excel某一列的固定内容&#xff0c;比如原内容是&#xff1a; thread entry i…