个人C++学习记录
目录
学习网站:
个人代码仓库
Gitcode
Github:
GitHub - MyDarkest/c-_study: My clone repository
关键字
#include
和python中import一样
#define
头文件
在visual studio中有一个“头文件”夹用于管理头文件
如果在源(.cpp)文件中定义类,则该类仅在该特定源文件中可用。在较大的程序中,通常希望使用在多个源文件中编写的类。
我们知道可以将函数声明放在头文件中。然后可以将这些函数声明#include到多个代码文件(甚至多个项目)中。类也不例外。类定义可以放在头文件中,然后#include在要使用类类型的任何其他文件中。
与只需要使用前向声明的函数不同,编译器通常需要查看类(或任何程序定义的类型)的完整定义,才能使用类型。这是因为编译器需要理解如何声明成员,以确保正确使用它们,并且它需要能够计算该类型的对象的大小,以便实例化它们。因此,头文件通常包含类的完整定义,而不仅仅是类的前向声明。
date.h
#pragma once
#ifndef DATA_H
#define DATA_H
class Date
{
private:
int m_year{};
int m_month{};
int m_day{};
public:
Date(int year, int month, int day);
void print() const;
int getYear() const { return m_year; }
int getMonth() const { return m_month; }
int getDay() const { return m_day; }
};
#endif
date.cpp
#include "Date.h"
#include <iostream>
Date::Date(int year,int month, int day)
:m_year{year}
, m_month{ month }
, m_day{ day }
{
}
void Date::print() const
{
std::cout << "Date(" << m_year << "," << m_month << "," << m_day << ")\n";
}
int main()
{
Date date(2023,12,31);
date.print();
std::cout << "Hello World!\n";
}
参考资料:
新建头文件:
void
在 C++ 中,void
作为函数返回类型时,表示这个函数不返回任何值。
void printHello() {
std::cout << "Hello" << std::endl;
}
const
接口
main
在 C++ 项目中,无论有多少个.cpp文件,程序的执行总是从main函数开始。main函数是 C++ 程序的入口点。例如,你有file1.cpp和file2.cpp两个文件,只有包含main函数的那个文件中的main函数会首先被执行。
输入、打印
输入
#include <iostream>
#include <string>
int main() {
std::string str;
std::cout << "请输入一个字符串:";
std::cin >> str;
std::cout << "你输入的字符串是:" << str << std::endl;
return 0;
}
打印
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
格式化输出
#include <iostream>
using namespace std;
#include<iomanip>
int main()
{
int b = 123456;
cout << b << endl;
cout << hex << b << endl; //十六进制 小写
cout << setiosflags(ios::uppercase) << b << endl; //十六进制 大写
cout << setw(10) << b << ',' << endl; // 填充空格
cout << setfill('*') << setw(10) << b << endl; // 填充*
cout << setiosflags(ios::showpos) << b << endl; // 十六进制 大写
}
#include <iostream>
using namespace std;
int main()
{
int x = 123;
double y = 3.1415;
cout << "x=";
cout.width(10); // 设置输出域宽为10
cout << x;
cout << "y=";
cout.width(10);
cout << y << endl;
cout.setf(ios::left); // 左对齐
cout << "x=";
cout.width(10); // 设置输出域宽为10
cout << x;
cout << "y=";
cout << y << "\n";
cout.fill('*'); // 设置*填充空位
cout.precision(4); // 设置精度4
cout.setf(ios::showpos); // 设置正数前显示“+”
cout << "x=";
cout.width(10); //设置输出域宽10
cout << x;
cout << "y=";
cout.width(10);
cout << y << endl;
}
输出结果
x= 123y= 3.1415
x=123 y=3.1415
x=+123******y=+3.142****
转义字符
换行符 | \n |
变量赋值
int x;
x = 12;
std::cout << x << endl;
{}花括号内赋值
在 C++ 中,int x { 5 };
这种写法是使用花括号初始化器(也称为统一初始化)来初始化变量 x
。
花括号初始化器是 C++11 引入的一种通用的初始化语法,它可以用于多种不同的场景,具有以下特点和优势:
- 避免类型收窄:花括号初始化会进行严格的类型检查,不允许进行可能导致数据丢失的类型收窄转换。例如:
// 以下代码会编译错误,因为从 double 到 int 的转换可能导致数据丢失
double d = 5.5;
int y { d };
- 可用于多种对象的初始化:不仅可以用于基本数据类型,还可以用于数组、结构体、类等复杂类型的初始化。例如:
// 初始化数组
int arr[]{1, 2, 3};
// 定义结构体
struct Point {
int x;
int y;
};
// 初始化结构体
Point p{3, 4};
- 聚合初始化:对于聚合类型(如数组和简单的结构体),可以使用花括号初始化来提供成员初始值列表。
对比传统的初始化方式:
// 传统的初始化方式
int a = 5;
// 使用花括号初始化
int b { 5 };
int a = 5;
是使用赋值初始化的方式,而 int b { 5 };
是使用花括号初始化。在大多数情况下,这两种方式对于基本数据类型的初始化效果是相同的,但在一些复杂场景下,花括号初始化的优势就会体现出来。
在这个示例中,展示了花括号初始化的不同用法,以及它如何避免类型收窄的问题。
#include <iostream>
int main() {
int x { 5 };
std::cout << "x: " << x << std::endl;
double d = 5.5;
// int y { d }; // 这行会导致编译错误,类型收窄
int y = static_cast<int>(d); // 正确的转换方式
std::cout << "y: " << y << std::endl;
int arr[]{1, 2, 3};
std::cout << "arr[0]: " << arr[0] << std::endl;
struct Point {
int x;
int y;
};
Point p{3, 4};
std::cout << "p.x: " << p.x << ", p.y: " << p.y << std::endl;
return 0;
}
if函数
#include <iostream>
int main() {
int num = -5;
if (num > 0) {
std::cout << num << "是正数" << std::endl;
} else {
std::cout << num << "是非正数" << std::endl;
}
return 0;
}
#include <iostream>
using namespace std;
int main() {
int ilnput;
cout<<"Input a value"<<endl;
cin>>ilnput; // 输入一个整数
if(ilnput%2!=0)
cout<<"The input is odd"<<endl;
else
cout<<"The input is even"<<endl;
return 0;
}
switch函数
#include <iostream>
int main() {
int day;
std::cout << "请输入一个数字(1-7),代表一周中的某一天:";
std::cin >> day;
switch (day) {
case 1:
std::cout << "星期一" << std::endl;
break;
case 2:
std::cout << "星期二" << std::endl;
break;
case 3:
std::cout << "星期三" << std::endl;
break;
case 4:
std::cout << "星期四" << std::endl;
break;
case 5:
std::cout << "星期五" << std::endl;
break;
case 6:
std::cout << "星期六" << std::endl;
break;
case 7:
std::cout << "星期日" << std::endl;
break;
default:
std::cout << "输入的数字不在1到7之间" << std::endl;
break;
}
return 0;
}
结构体 struct
参考资料:结构体简介 – C++学习网
结构体成员默认是public
#include <iostream>
struct Employee
{
int id {};
int age {};
double wage {};
};
int main()
{
Employee joe {};
joe.id = 14;
joe.age = 32;
joe.wage = 60000.0;
Employee frank {};
frank.id = 15;
frank.age = 28;
frank.wage = 45000.0;
int totalAge { joe.age + frank.age };
if (joe.wage > frank.wage)
std::cout << "Joe makes more than Frank\n";
else if (joe.wage < frank.wage)
std::cout << "Joe makes less than Frank\n";
else
std::cout << "Joe and Frank make the same amount\n";
// Frank 升职加薪了
frank.wage += 5000.0;
// 今天是joe的生日
++joe.age; // Joe 的年龄加一
return 0;
}
结构体内传入函数
#include <iostream>
struct Date {
public:
int year{};
int month{};
int day{};
void print() //定义成员函数print
{
std::cout << day << '/' << month << '/' << year;
}
};
int main()
{
Date date{ 2020, 10, 21 };
date.day = 31;
date.print();
return 0;
}
结构体聚合初始化
struct Employee
{
int id {};
int age {};
double wage {};
};
int main()
{
Employee frank = { 1, 32, 60000.0 }; // 拷贝列表初始化
Employee joe { 2, 28, 45000.0 }; // 列表初始化 (推荐)
return 0;
}
类 class
默认情况下类成员是private,要加public才能访问
#include <iostream>
class Date {
public:
int m_day{};
int m_month{};
int m_year{};
};
void printDate(const Date& date)
{
std::cout << date.m_day << '/' << date.m_month << '/' << date.m_year;
}
int main()
{
Date date{ 4, 10, 21 };
printDate(date);
return 0;
}
#include <iostream>
class Date {
public:
void print() //定义成员函数print
{
std::cout << day << '/' << month << '/' << year;
}
private:
int year{2020};
int month{14};
int day{10};
};
int main()
{
Date date{};
date.print();
return 0;
}
输出结果:10/14/2020
#include <iostream>
#include <string>
#include <string_view>
class Person {
private:
std::string m_name{};
public:
void kisses(const Person& p) const
{
std::cout << m_name << " kisses " << p.m_name << '\n';
}
void setName(std::string name)
{
m_name = name;
}
};
int main()
{
Person joe;
joe.setName("Joe");
Person kate;
kate.setName("Kate");
joe.kisses(kate);
return 0;
}
输出结果:Joe kisses Kate
参考资料:class简介 – C++学习网
结构体(struct)和类(class)的区别
类:
访问权限:将其成员默认设置为private
结构体:
访问权限:将其成员默认设置为public。
根据经验法则,在满足以下所有条件时使用结构体:
- 有一个简单的数据集合,不能从限制访问中受益。
- 聚合初始化已足够。
- 没有类不变量、设置限制或清理需要。
可以在何处使用结构体的几个示例:constexpr全局程序数据、简单结构(例如int成员的简单集合,不能从私有化中受益)、用于从函数返回一组数据的结构。
否则使用类。
我们希望结构体是聚合。因此,如果您使用任何使结构成为非聚合的功能,那么您可能应该改用类(并遵循类的所有最佳实践)。
参考资料:
for 循环
#include <iostream>
int main() {
int sum = 0;
// for循环从1迭代到10
for (int i = 1; i <= 10; i++) {
sum += i;
}
std::cout << "1到10的整数之和为: " << sum << std::endl;
return 0;
}
for 循环 嵌套
#include <iostream>
int main() {
// 外层循环控制行数
for (int i = 1; i <= 9; i++) {
// 内层循环控制列数
for (int j = 1; j <= i; j++) {
std::cout << j << "×" << i << "=" << i * j << "\t";
}
std::cout << std::endl;
}
return 0;
}
break
for(int i = 0; i < 10; i++){
if(i == 5){
break; // 当i等于5时,跳出循环
}
// 循环体
}
return
#include <iostream>
int findFirstEven(int arr[], int size) {
for(int i = 0; i < size; i++){
if(arr[i] % 2 == 0){
return arr[i]; // 找到第一个偶数,返回该数并退出循环和函数
}
}
return -1; // 如果没有找到偶数,返回-1
}
int main() {
int arr[] = {1, 3, 5, 6, 7};
int result = findFirstEven(arr, 5);
std::cout << "第一个偶数是:" << result << std::endl;
return 0;
}
continue
for(int i = 0; i < 10; i++){
if(i == 5){
continue; // 当i等于5时,跳过本次循环的剩余代码,进入下一次循环
}
// 循环体
}
while循环
#include <iostream>
int main() {
int sum = 0;
int i = 1;
// 只要 i 小于等于 10,就执行循环
while (i <= 10) {
sum += i;
i++; // 让 i 的值递增,以便最终使条件表达式为 false
}
std::cout << "1 到 10 的整数之和为:" << sum << std::endl;
return 0;
}
无限循环
while (true) {
// 循环体语句,不会自动终止,需要在循环体内部使用 break 等语句退出循环
}
嵌套循环
#include <iostream>
int main() {
int i = 1;
// 外层循环控制行数
while (i <= 9) {
int j = 1;
// 内层循环控制列数
while (j <= i) {
std::cout << j << "×" << i << "=" << i * j << "\t";
j++;
}
std::cout << std::endl;
i++;
}
return 0;
}
break
#include <iostream>
int main() {
int i = 0;
while (true) { // 条件为 true,会一直循环,除非使用 break 终止
if (i == 5) {
break; // 当 i 等于 5 时,终止循环
}
std::cout << i << " ";
i++;
}
std::cout << std::endl;
return 0;
}
return
#include <iostream>
void printNumbers() {
int i = 0;
while (i < 10) {
if (i == 5) {
std::cout << std::endl << "Reached 5, exiting function." << std::endl;
return; // 当 i 等于 5 时,退出函数
}
std::cout << i << " ";
i++;
}
}
int main() {
printNumbers();
return 0;
}
continue
#include <iostream>
int main() {
int i = 0;
while (i < 10) {
i++;
if (i % 2 == 0) {
continue; // 当 i 是偶数时,跳过后续代码,进入下一次循环判断
}
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
访问级别摘要
访问级别 | 访问说明符 | 成员可访问 | 子类可访问 | public可访问 |
---|---|---|---|---|
公共 | public: | 是 | 是 | 是 |
受保护 | protected: | 是 | 是 | 否 |
私有 | private: | 是 | 否 | 否 |
析构函数
参考资料:析构函数简介 – C++学习网
它们是在创建非聚合类类型的对象时调用的特殊成员函数。构造函数用于初始化成员变量,并执行所需的任何其他设置任务,以确保类的对象可以使用。
类似地,类具有另一种类型的特殊成员函数,该函数在销毁非聚合类类型的对象时自动调用。该函数称为析构函数。析构函数被设计为允许类在销毁类的对象之前进行任何必要的清理。
与构造函数一样,析构函数具有特定的命名规则:
- 构造函数的名字需要与类名一致,同时需要带一个前缀波浪号( ~ )
- 析构函数不能有参数
- 析构函数不能有返回类型
通常,您不应该显式调用析构函数(因为当对象被销毁时它将自动调用),因为很少有情况下您希望多次清理对象。
析构函数可以安全地调用其他成员函数,因为对象直到析构函数执行后才被销毁。
参考资料: