C++ 复习总结记录四

C++ 复习总结记录四

主要内容

1、构造函数其它要点

2、static 成员

3、友元

4、内部类

5、匿名对象

6、拷贝对象时编译器的优化

一 构造函数其它要点

1.1 构造函数体赋值

创建对象时,编译器调用构造函数,给对象中各个成员变量一个合适初始值

class Date
{public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};

上述过程不能称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值。因为初始化只能初始化一次,而构造函数体内可以多次赋值

1.2 初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式

class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};

【注意】

1、每个成员变量在初始化列表中只能出现一次 (初始化只能初始化一次)

2、类中包含以下成员,必须放在初始化列表位置进行初始化

  • 引用成员变量
  • const 成员变量
  • 自定义类型成员 ( 且该类没有默认构造函数时 )
class A
{
public:A(int a):_a(a){}
private:int _a;
};class B
{
public:B(int a, int ref):_aobj(a),_ref(ref),_n(10){}private:A _aobj;  // 没有默认构造函数int& _ref;  // 引用const int _n; // const 
};

3、尽量使用初始化列表初始化,对于自定义类型成员变量,一定会使用默认构造初始化

class Time
{
public:Time(int hour = 0):_hour(hour){cout << "Time()" << endl;}private:int _hour;
};class Date
{
public:Date(int day){}private:int _day;Time _t;
};int main()
{Date d(1);
}

4、成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print() {cout<<_a1<<" "<<_a2<<endl;}private:int _a2;int _a1;
};
int main() {A aa(1);aa.Print(); //输出1  随机值
}

1.3 explicit 关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用

class Date
{public:// 1. 单参构造函数, 没有使用 explicit 修饰,具有类型转换作用// explicit 修饰构造函数, 禁止类型转换 -- explicit去掉之后,代码可以通过编译explicit Date(int year):_year(year){}// 2. 虽然有多个参数, 但是创建对象时后两个参数可以不传递, 没有使用explicit 修饰,具有类型转换作用// explicit 修饰构造函数,禁止类型转换/*explicit Date(int year, int month = 1, int day = 1): _year(year), _month(month), _day(day){}*/Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}private:int _year;int _month;int _day;
};
void Test()
{Date d1(2022);// 用一个整形变量给日期类型对象赋值// 实际编译器背后会用 2023 构造一个无名对象,最后用无名对象给 d1 对象进行赋值d1 = 2023;// 将 1 蔽掉, 2 放开时则编译失败,因为 explicit 修饰构造函数,禁止了单参构造函数类型转换的作用
}

用 explicit 修饰构造函数,禁止单参或缺省单参的构造函数隐式转换

二 static 成员

2.1 概念

声明为 static 的类成员称为类的静态成员,用 static 修饰的成员变量,称之为静态成员变量;用 static 修饰的成员函数,称为静态成员函数。静态成员变量必须在类外进行初始化

实现一个类,计算程序当前有多少个类对象

class A
{
public:A() { ++_scount; }A(const A& t) { ++_scount; }~A() { --_scount; }static int GetACount() { return _scount; }private:static int _scount;
};int A::_scount = 0;
void TestA()
{cout << A::GetACount() << endl;A a1, a2;A a3(a1);cout << A::GetACount() << endl;
}

2.2 特性

1、静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区

2、静态成员变量必须在类外定义,定义时不添加 static 关键字,类中只是声明

3、类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问

4、静态成员函数没有隐藏的 this 指针,不能访问任何非静态成员

5、静态成员也是类的成员,受 public、protected、private 访问限定符的限制

练习

1、静态成员函数可以调用非静态成员函数吗 【不可以】

2、非静态成员函数可以调用类的静态成员函数吗 【可以】

三 友元

友元提供了一种突破封装的方式,有时提供了便利。但友元会增加耦合度,破坏了封装,所以不宜多用。友元分为:友元函数友元类

3.1 友元函数

不适用友元去重载 operator<<,会发现无法将 operator<< 重载为成员函数

因为 cout 的输出流对象和隐含的 this 指针在抢占第一个参数的位置。this 指针默认是第一个参数(也就是左操作数)。但实际使用中 cout 需要是第一个形参对象,才能正常使用。所以要将 operator<< 重载成全局函数,但又会导致类外没办法访问成员,此时就需要友元来解决(operator>> 同理)

class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用// 成员函数第一个参数一定是隐藏 this, 所以 d1 必须放在 << 左侧ostream& operator<<(ostream& _cout){_cout << _year << "-" << _month << "-" << _day << endl;return _cout;}private:int _year;int _month;int _day;
};

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加 friend 关键字

class Date
{friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout; 
}istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}int main()
{Date d;cin >> d;cout << d << endl;return 0;
}

注意

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用 const 修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

3.2 友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员

  1. 友元关系是单向的,不具有交换性 ( 比如上述 Time 类和 Date 类,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接访问 Time 类的私有成员变量,但在 Time 类中访问 Date 类中私有的成员变量则不行 )
  2. 友元关系不能传递( 如果 C 是 B 的友元, B 是 A 的友元,则不能说明 C 是 A 的友元 )
  3. 友元关系不能继承
class Time
{friend class Date;   // 声明日期类为时间类的友元类, 则在日期类中就直接访问 Time 类中的私有成员变量
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){}private:int _hour;int _minute;int _second;
};class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}private:int _year;int _month;int _day;Time _t;
};

四 内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员,外部类对内部类没有任何优越的访问权限。

注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员,但是外部类不是内部类的友元

特性

1、内部类可以定义在外部类的 public、protected、private 都可

2、注意内部类可以直接访问外部类中的 static 成员,不需要外部类的对象/类名

3、sizeof(外部类) = 外部类,和内部类没有任何关系

class A
{
private:static int k;int h;public:class B // B 天生就是 A 的友元{public:void foo(const A& a){cout << k << endl; // 静态成员直接访问cout << a.h << endl; // 非静态成员使用对象访问}};
};int A::k = 1;
int main()
{A::B b;b.foo(A());return 0;
}

五 匿名对象

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}private:int _a;
};class Solution {public:int Sum_Solution(int n) {//...return n;}
};int main()
{A aa1;//A aa1(); 不能这样定义对象, 因为编译器无法识别是一个函数声明, 还是对象定义. 但可以这么定义匿名对象, 匿名对象的特点是不用取名字, 但它的生命周期只有这一行, 可以看到下一行它就会自动调用析构函数A();// 匿名对象在仅调用一次成员函数的场景下很好用, 例如Solution().Sum_Solution(10);return 0;
}

六 拷贝对象时编译器的优化

在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝,这个在一些场景下非常有用

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a = aa._a;}return *this;}~A(){cout << "~A()" << endl;}private:int _a;
};void f1(A aa)
{}A f2()
{A aa;return aa;
}int main()
{// 传值传参, 打印结果/*A(int a)A(const A& aa)~A()*/~A()A aa1;f1(aa1);cout << endl;// 传值返回, 打印结果/*A(int a)~A()查看反汇编这里并没有内联一个表达式中, 连续构造 + 拷贝构造 -> 优化为直接构造*/f2();cout << endl;// 隐式类型, 连续构造 + 拷贝构造 -> 优化为直接构造f1(1);// 一个表达式中, 连续构造 + 拷贝构造 -> 优化为一个构造f1(A(2));cout << endl;// 一个表达式中, 连续拷贝构造 + 拷贝构造 -> 优化为一个构造A aa2 = f2();cout << endl;// 一个表达式中, 连续拷贝构造 + 赋值重载 -> 优化一个拷贝构造aa1 = f2();cout << endl;return 0;
}

七 练习

1、求 1 + 2 + 3 + … + n,要求不能使用乘除法、for、while、if、else、switch、case 等关键字及条件判断语句 ( A ? B : C ) OJ链接

使用类静态成员 + 构造函数

注 clang 编译器支持动态数组的语法

class Test
{
public:Test(){num += 1;sum += num;}static int getSum(){return sum;}private:static int num;static int sum;
};
int Test::num = 0;
int Test::sum = 0;class Solution {
public:int Sum_Solution(int n) {Test test[n];return Test::getSum();}
};

递归需要终止条件,不能用 if 终止,那么只能用逻辑运算符了

class Solution {
public:int Sum_Solution(int n) {int sum = n;sum && (sum += Sum_Solution(n - 1));return sum;}
};

等差数列求和公式:n * (n+1) / 2 = (n^2 + n) / 2 ,不能用除法,因此可以右移一位表示除以 2

class Solution {
public:int Sum_Solution(int n) {return (int)(pow(n, 2) + n) >> 1;}
};

2、计算日期到天数的转换 OJ 链接

#include <iostream>
using namespace std;// 获取某年某月的天数
int GetMonthDay(int year, int month) {static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };int day = days[month];if (month == 2&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {day += 1;}return day;
}int getDayNum(int year, int month, int day) {int res = day;--month;while (month > 0) {res += GetMonthDay(year, month--);}return res;
}int main() {int a, b, c;while (cin >> a >> b >> c) {}cout << getDayNum(a, b, c) << endl;
}

3、日期差值 OJ 链接

#include <iostream>
using namespace std;class Date {public:Date(int num) {//拆分_day = num % 100, num  /= 100;_month = num % 100, num  /= 100;_year = num;}int GetMonthDay(int year, int month) {static int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };int res = days[month];if (month == 2 && ((year % 4 == 0  && year % 100 != 0)|| year % 400 == 0)) {++res;}return res;}bool operator<(const Date& d) const {if (_year < d._year) return true;else if (_year > d._year) return false;else {if (_month < d._month) return true;else if (_month > d._month) return false;else {if (_day < d._day) return true;else if (_day > d._day) return false;}}return false;}bool operator!=(const Date& d) const {if (_year == d._year &&  _month == d._month && _day == d._day)  return false;else return true;}Date& operator+=(int day) {_day += day;while (_day > GetMonthDay(_year, _month)) {_day -= GetMonthDay(_year, _month);_month++;if (_month == 13) {_year++;_month = 1;}}return *this;}Date& operator++() {*this += 1;return *this;}int operator-(const Date& d) const {Date max = *this;Date min = d;int status = 1;if (max < min) {max = d;min = *this;status = -1;}int day = 0;while (min < max) {++min, ++day;}return day + 1;}private:int _year = 0;int _month = 0;int _day = 0;
};int main() {int a, b;while (cin >> a >> b) {}cout << Date(a) - Date(b)  << endl;
}

4、打印日期 OJ 链接

#include <cstdio>
#include <iostream>
using namespace std;int getMonthDay(int year, int month)
{static int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int day = days[month];if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)){day++;}return day;
}void printDate(int year, int day)
{int month = 1;while (day > getMonthDay(year, month)){day -= getMonthDay(year, month);++month;}printf("%04d-%02d-%02d\n", year, month, day);
}int main() {int a, b;while (cin >> a >> b) {printDate(a, b);}
}

5、累加天数 OJ 链接

#include <cstdio>
#include <iostream>
using namespace std;int getMonthDay(int year, int month)
{static int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int res = days[month];if(month == 2 && ((year % 4 == 0 && year % 100 != 0)|| year % 400 == 0)){res++;}return res;
}void printDate(int year, int month, int day, int cnt)
{while (cnt) {++day;if (day > getMonthDay(year, month)) {day = 1;++month;if (month > 12) {month = 1;++year;}}--cnt;}printf("%04d-%02d-%02d\n", year, month, day);
}int main() {int m, a, b, c, d;cin >> m;for (int i = 0 ; i < m; ++i){cin >> a >> b >> c >> d;printDate(a, b, c, d);}
}

C 中的 bool 类型

_Bool C99 标准引入的新关键字,sizeof(_Bool) 该类型占一个字节,且给这个类型变量赋任何非 0 整数值,其值都是 1

/*
* ISO C Standard: 7.16 Boolean type and values
*/#ifndef _STDBOOL_H#define _STDBOOL_H#ifndef __cplusplus#define bool _Bool#define true 1#define false 0#else /* __cplusplus *//* Supporting in C++ is a GCC extension. */#define _Bool bool#define bool bool#define false false#define true true#endif /* __cplusplus *//* Signal that all the definitions are present. */#define __bool_true_false_are_defined 1#endif /* stdbool.h */

C 变长数组不能初始化(clang 编译器支持)

#include<stdio.h>
int main(){int n = 5;int arr[n];return 0;
}

编译一般是会报错的,但是这其实并不算一种语法错误。C99 标准前是不支持变长数组的,[] 里只能是常量。C99增加了对变长数组的支持,但普遍的编译器并不支持 C99(例如 VS)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Robot---奇思妙想轮足机器人

1 背景 传统机器人有足式、轮式、履带式三种移动方式&#xff0c;每种移动方式都有各自的优缺点。轮式机器人依靠车轮在地面上移动&#xff0c;能源利用率高、移动速度快&#xff0c;但是仅以轮子与地面接触&#xff0c;缺乏越障能力和对复杂地形的适应能力&#xff0c;尤其面对…

用JAVA编写一个简单的小游戏

用Java语言编写一个简单的小游戏。这里是一个非常基础的猜数字小游戏的代码示例。在这个游戏中&#xff0c;程序会随机选择一个1到100之间的整数&#xff0c;玩家需要猜测这个数字是什么。每次猜测后&#xff0c;程序会告诉玩家他们猜的数字是太高了、太低了还是正确。 impor…

加速科技荣获“浙江省企业研究院”认定

近日&#xff0c;浙江省经济和信息化厅公布“2024年认定&#xff08;备案&#xff09;省级企业研发机构名单”。经过多轮严格评审和公示&#xff0c;加速科技荣获“省企业研究院”认定。这是加速科技继获国家级专精特新“小巨人”企业认定荣誉后的又一里程碑。 “浙江省企业研究…

MySQL使用navicat新增触发器

找到要新增触发器的表&#xff0c;然后点击设计&#xff0c;找到触发器标签。 根据实际需要&#xff0c;填写相关内容&#xff0c;操作完毕&#xff0c;点击保存按钮。 在右侧的预览界面&#xff0c;可以看到新生成的触发器脚本

性能测试05|JMeter:分布式、报告、并发数计算、性能监控

目录 一、JMeter分布式 1、应用场景 2、原理 3、分布式相关注意事项 4、分布式配置与运行 二、JMeter报告 1、聚合报告 2、HTML报告 三、并发用户数&#xff08;线程数&#xff09;计算 四、JMeter下载第三方插件 五、性能监控 1、Concurrency Thread Group 线程组…

(已开源-AAAI25) RCTrans:雷达相机融合3D目标检测模型

在雷达相机融合三维目标检测中&#xff0c;雷达点云稀疏、噪声较大&#xff0c;在相机雷达融合过程中提出了很多挑战。为了解决这个问题&#xff0c;我们引入了一种新的基于query的检测方法 Radar-Camera Transformer (RCTrans)。具体来说&#xff1a; 首先设计了一个雷达稠密…

Python----Python爬虫(利用bs4、pyquery、xpath爬取电影名和评分)

电影网址电影大全_好看的电影_最新好看的电影_电影排行榜-影视快搜 一、bs4 import requests from fake_useragent import UserAgent from bs4 import BeautifulSoup # 设置URL地址 urlhttp://kan.znds.com/movie/ # 设置请求头 headers{User-Agent:UserAgent().edge} # 发送…

Hbuilder ios 离线打包sdk版本4.36,HbuilderX 4.36生成打包资源 问题记录

1、打包文档地址https://nativesupport.dcloud.net.cn/AppDocs/usesdk/ios.html#%E9%85%8D%E7%BD%AE%E5%BA%94%E7%94%A8%E7%89%88%E6%9C%AC%E5%8F%B7 2、配置应用图标 如果没有appicon文件&#xff0c;此时找到 Assets.xcassets 或者 Images.xcassets(看你sdk引入的启动文件中…

TCP通信原理学习

TCP三次握手和四次挥手以及为什么_哔哩哔哩_bilibili

unity学习13:gameobject的组件component以及tag, layer 归类

目录 1 gameobject component 是unity的基础 1.1 类比 1.2 为什么要这么设计&#xff1f; 2 从空物体开始 2.1 创建2个物体 2.2 给 empty gameobject添加组件 3 各种组件和新建组件 3.1 点击 add component可以添加各种组件 3.2 新建组件 3.3 组件的操作 3.4 特别的…

MYSQL--------什么是存储过程和函数

什么是存储过程和函数 存储过程&#xff1a; 存储过程是一组预编译的 SQL 语句集合&#xff0c;存储在数据库服务器中&#xff0c;可通过名称调用执行。它可以包含数据操作语言&#xff08;DML&#xff09;、数据定义语言&#xff08;DDL&#xff09;、控制流语句等。存储过程主…

计算机网络 (30)多协议标签交换MPLS

前言 多协议标签交换&#xff08;Multi-Protocol Label Switching&#xff0c;MPLS&#xff09;是一种在开放的通信网上利用标签引导数据高速、高效传输的新技术。 一、基本概念 MPLS是一种第三代网络架构技术&#xff0c;旨在提供高速、可靠的IP骨干网络交换。它通过将IP地址映…

探索Facebook的区块链计划:未来社交网络的变革

随着区块链技术的迅速发展&#xff0c;社交网络领域正面临一场深刻的变革。Facebook&#xff0c;作为全球最大且最具影响力的社交平台之一&#xff0c;正在积极探索区块链技术的应用。本文将深入探讨Facebook的区块链计划&#xff0c;分析其潜在的变革性影响&#xff0c;并展望…

十年后LabVIEW编程知识是否会过时?

在考虑LabVIEW编程知识在未来十年内的有效性时&#xff0c;我们可以从几个角度进行分析&#xff1a; ​ 1. 技术发展与软件更新 随着技术的快速发展&#xff0c;许多编程工具和平台不断更新和改进&#xff0c;LabVIEW也不例外。十年后&#xff0c;可能会有新的编程语言或平台…

C# async和await

第一种&#xff1a; 多个异步任务按照顺序执行先让一个异步任务start 然后通过ContinueWith方法 在参数函数的表达式里面开启第二个任务如果要有第三个任务 需要在第二个任务ContinueWith方法中开启第三个任务 以此类推 可以实现多个异步任务顺序执行 上面这种方式绘出现地狱回…

Excel 技巧03 - 如何对齐小数位数? (★)如何去掉小数点?如何不四舍五入去掉小数点?

这几个有点儿关联&#xff0c;我都给放到一起了&#xff0c;不影响大家分别使用。 目录 1&#xff0c;如何对齐小数位数&#xff1f; 2&#xff0c;如何去掉小数点&#xff1f; 3&#xff0c;如何不四舍五入去掉小数点&#xff1f; 1&#xff0c;如何对齐小数位数&#xff…

node.js|浏览器插件|Open-Multiple-URLs的部署和使用,实现一键打开多个URL的强大工具

前言&#xff1a; 在整理各类资源的时候&#xff0c;可能会面临资源非常多的情况&#xff0c;这个时候我们就需要一款能够一键打开多个URL的浏览器插件了 说简单点&#xff0c;其实&#xff0c;迅雷就是这样的&#xff0c;但是迅雷是基于内置nginx浏览器实现的&#xff0c;并…

“AI 视频图像识别系统,开启智能新视界

咱老百姓现在的生活啊&#xff0c;那是越来越离不开高科技了&#xff0c;就说这 AI 视频图像识别系统&#xff0c;听起来挺高大上&#xff0c;实际上已经悄无声息地融入到咱们日常的方方面面&#xff0c;给咱带来了超多便利。 先讲讲安防领域吧&#xff0c;这可是 AI 图像识别的…

C语言 游动的小球

代码如下&#xff1a; 在这里插入代码片#include<stdio.h> #include<stdlib.h> #include<windows.h>int main() {int i,j;int x 5;int y 10;int height 20;int velocity_x 1;int velocity_y 1;int left 0;int right 20;int top 0;int bottom 10;while(1){…

基于SpringBoot实现的保障性住房管理系统

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…