======C++ 初探======
//第 1 章笔记//
----
====HelloWorld====
===函数===
* 函数:一段可以被反复调用的代码,包含:
* 返回类型(''void'' 为不返回)
* 函数名:用于调用
* 形参列表:表示函数接收的参数类型,可以为空,为 ''void'',可以无形参
* 函数体:具体的执行逻辑
// int 是返回类型
// main 后的括号是形参列表(为空)
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}
// pInfo 是 parameter
// test1, test2 是 argument
void fun(const char* pInfo)
{
std::cout << pInfo << std::endl;
}
// 无形参的写法
// 通常是执行逻辑中不包含变量,但为了接口需要保留该变量的形参位置
// 因此只写形参类型
void fun2(const char* pInfo, int)
{
std::cout << pInfo << std::endl;
}
int main(int argc, char const *argv[])
{
fun("test1");
fun2("test2", 1);
return 0;
}
===Main函数===
* ''main'' 是整个程序的入口,是操作系统调用 C++ 的接口
* 返回值为 ''int'', ''0'' 为正常返回。没有 ''return'' 默认 ''main'' 返回 ''0''
linux 下可以通过下面的命令检查程序的返回值(是否成功运行):
#check the return type of the program
$echo $?
==main 的形参列表==
int main(int argc, char* argv[]) {}
===其他内容===
* 类型:C++ 引入的,用于赋予某段连续内存空间意义
* 语句:表明执行的操作
* 注释:单行,多行
====系统 IO====
// 定义于 iostream 中
// 如果使用双引号,系统会在当前目录中找
// 如果使用三角括号,系统会优先找库中的内容
// 自定义 header 通常给 .h 后缀
#include
#include "myheader.h"
===Iostream===
* 输入流:''cin''
* 输出流:''cout'' / ''cerr'' / ''clog''
* ''cerr'' 可以定向到不同的文件中,作为错误的输出
#cout 的内容会输出到 OutputText
#cerr 的内容会输出到 ErrorText
./main > OutputText 2>ErrorText
* ''clog'' 与 ''cerr'' 的区别在于是否立即刷新**缓冲区**:
* ''cerr'' 输出的是错误信息,因此需要立即刷新缓冲区
* ''clog'' 输出的是日志信息,因此不会立即刷新缓冲区
* 手动刷新:''std::flush'' / ''std::endl'',但大量刷新存在性能问题,因此推荐只在必要的时候使用。
缓冲区是内存中的一个区域,用于优化读写的速度。缓冲区满了以后,会一次性将内容输出。但问题在于,程序没有正常结束时,缓冲区中的内容会丢失。如果为了查找程序的 Bug,那么这部分内容是需要保留的。这种情况下,需要立即刷新缓冲区。
===命名空间===
命名空间的存在是为了防止命名冲突。多人开发的过程中很可能会存在同名函数,放在一起可能会存在调用的冲突。这种情况下可以选择将其分置于不同的命名空间内:
namespace NS1 {
void fun() {
std::cout << "NS1" << std::endl;
}
}
namespace NS2 {
void fun() {
std::cout << "NS2" << std::endl;
}
}
没有标明命名空间的函数属于**全局空间**(//global space//):
void fun()
{
std::cout << "global fun";
}
调用的方式有三种:
* ''::'' 域解析符调用:
// call
int main(int argc, char const *argv[])
{
NS1::fun();
NS2::fun();
}
* ''using'' 调用
using namespace NS1;
fun();
# output
# 如果 NS1 中定义了 fun()
NS1
# 如果 NS1 中没有定义 fun(), 全局中定义了 fun()
global fun
* 如果都定义了 ''fun()'',课程中说会先调用全局 ''fun()'',但测试发现 gcc 13.1.0 报错二义性。慎用
* ''using'' 会导致整个命名空间暴露给其他使用者,应当尽量使用域解析符。
* 名字空间别名:使用别名代替完整的命名空间名进行调用:
namespace n = NS1;
n::fun();
==std 命名空间==
* std 命名空间是 C++ 标准库的命名空间,用法与上述的命名空间用法相同。
* name mangling:C++ 会为不同命名空间下的相同 name 进行变化,为链接使用:
# checking the mangling data
nm main.o - o
# demangling,查看 mangling 之前的原始数据
nm main.o - o | c++filt -t
''main()'' 不会做 mangling,因为 ''main()'' 是唯一的。
====控制流====
* if statement:通过选择分支来选择执行的代码
* 条件部分:判断是否执行
* 使用**相等**(''=='')而不是**赋值** ''=''
* 赋值表达式会被解释为 (y = 42 -> 42),而 42 会被转化为布尔值 ''true'',因此赋值表达式恒为真。
* 使用 ''const'' 阻止赋值表达式作为调价
* 语句部分:要执行的操作
* while statement:循环条件判断
====结构体 / 自定义类型====
* 结构体:可以将不同的数据放置在一起,并使用 ''.'' 操作符访问内部元素
* 结构体可以作为参数被传入函数
* 结构体可以设置自己的成员函数
struct Point
{
int x = 1;
int y = 2;
//member function
Point fun(Point p)
{
p.x += 1;
p.y += 1;
return p;
}
};
int main(int argc, char const *argv[])
{
Point p;
//call
p = p.fun(p);
std::cout << p.x << " " << p.y << std::endl;
}