学习链接

【【1】【Cherno C++】【中字】欢迎来到C++】https://www.bilibili.com/video/BV1uy4y167h2?vd_source=8b78b27b693441a5dd061787497a5237

C++的基本语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
//iosrteam库包含istream和ostream分别表示输入流和输出流
int main() {
/*
* std为命名空间
* ::为作用域运算符
istream类型对象: cin 标准输入
ostream类型对象: cout 标准输出 cerr 错误和警告信息 clog 一般性信息

*/
std::cout << "hello,cpp" << std::endl << "please input num:";//; // 输出运算符 <<
int v1 = 0, v2 = 0;
std::cin >> v1 >> v2; // 输入运算符 >>
std::cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << std::endl;
// endl 操作符 结束当前行,并将于设备关联的缓冲区(buufer)中的内容刷到设备中


//计算数量不定的输入数据
std::cout << "计算多个整数" << std::endl;
int value = 0;
int sum = 0;
while (std::cin >> value)//遇到文字结束符“windows下为Ctrl+Z”或非int型数据结束循环
sum += value;
std::cout << "结果为:" << sum << std::endl;

return 0;
}

cout < < endl;
相当于
cout < < ”\n”< < flush;
缓冲区相关知识

类类型(一种数据结构)

类类型后缀名一般为.h
每个类实际上都定义了一个新类型

1
2
3
item.h  //新定义一个名为hello新类型
item object //object是一个hello类型的对象


不要把using声明放在头文件中!!!
http://t.csdn.cn/AE2wi
头文件中一般是声明类,包括类的成员,方法,还有函数原型,以及一些define等,但是不写出来具体的实现方法,而源文件主要是写类中声明的函数的具体实现方法。


C++ Primer 第2章

基本内置类型

算数类型

   算数类型可

C++ 单例模式

Meyers’ Singleton

利用了C++11中static变量的线程安全特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>


class Singleton
{
private:
static Singleton* s_Instance;
public:
static Singleton& Get() { return *s_Instance; }
void Hello() {}
};


Singleton* Singleton::s_Instance = nullptr;


int main()
{

Singleton::Get().Hello();
std::cin.get();

}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>


class Singleton
{

public:
static Singleton& Get() {
static Singleton Instance;
return Instance;
}
void Hello() {}
};


int main()
{

Singleton::Get().Hello();
std::cin.get();

}

饿汉式单例模式

懒汉式单例模式

双重检查锁


C++ static关键字

static关键词

static

类外面的static,意味着你声明为satatic的符号,连接将只是在内部,只能对你定义它的翻译单元可见

使用static修饰的静态函数或静态变量只会在它被声明的C++文件中被“看到”

s_Var常用这种方式表示静态变量

extern意味着它会在外部翻译单元中寻找s_Var变量

类内部的static待续~~~~~~~~~~~~~

尽量使用局部变量而不是全局变量,全局变量容易出现bug

在头文件声明静态变量包含在多个C++文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
示例:
Static.cpp

static int s_Varible = 5; //只能对你定义它的翻译单元可见

Main.cpp
#include<iostream>
int s_Varible = 10;
int main()
{
std::cout << s_Varible << std::endl;
}
//输出为10

Static.cpp
int s_Varible = 5;

Main.cpp
#include<iostream>
extern int s_Varible //在外部翻译单元寻找变量
int main()
{
std::cout << s_Varible << std::endl;
}
//输出为5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//function.h
#pragma once

void test1();
void test2();


//headtest.h
#pragma once
static int s_Var = 1;

//example1.cpp
#include<iostream>
#include "headtest.h"
void test1() {

std::cout << s_Var << std::endl;
s_Var++;

}

//example2.cpp
#include<iostream>
#include "headtest.h"
void test2() {

std::cout << s_Var << std::endl;


}
//main.cpp
#include<iostream>
#include "function.h"
int main() {

test1();
test2();
std::cin.get();
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//function.h
#pragma once

void test1();
void test2();


//headtest.h
#pragma once
extern int s_Var = 1;

//example1.cpp
#include<iostream>
#include "headtest.h"
void test1() {

std::cout << s_Var << std::endl;
s_Var++;

}

//example2.cpp
#include<iostream>
#include "headtest.h"
void test2() {

std::cout << s_Var << std::endl;


}
//main.cpp
#include<iostream>
#include "function.h"
#include "headtest.h"
int s_Var = 1;
int main() {

test1();
test2();
std::cin.get();
}


静态方法没有类实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>


struct Entity //聚合类
{
int x, y;

void Print()
{
std::cout << x << ", " << y << std::endl;
}


};


int main(){
Entity e;
e.x = 2;
e.y = 3;

Entity e1;
e1 = { 5 ,8 }; //聚合类
e.Print();
e1.Print();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>


struct Entity
{
static int x, y;

static void Print()
{
std::cout << x << ", " << y << std::endl;
}


};


int Entity::x;
int Entity::y;

int main(){
Entity e;
Entity::x = 2; //e.x = 2;
Entity::y = 3; //e.y = 3;

Entity e1;
Entity::x = 5; //e1.x = 5;
Entity::y = 8; //e1.y = 8;

Entity::Print(); //e.Print();
Entity::Print(); //e1.Print();
}

C++中的局部变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>


void Function()
{
int i = 0;
i++;
std::cout << i << std::endl;


}


int main()
{
Function();
Function();
Function();
Function();
Function();
std::cin.get();

}


局部变量生存期自函数调用到函数返回

作用域为函数内部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

int i = 0;
void Function()
{

i++;
std::cout << i << std::endl;


}


int main()
{
Function();
Function();
Function();
Function();
Function();
std::cin.get();

}

全局变量生存期为整个程序的生存期,作用域:全局作用域(只需要在一个源文件中定义,就可以作用于所有的源文件);
引用方法:其他文件如果要使用,必须用extern 等关键字声明要引用的全局变量;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

int i = 0;
void Function()
{

i++;
std::cout << i << std::endl;


}


int main()
{
Function();
i = 100;
Function();
Function();
Function();
Function();
std::cin.get();

}


全局变量能被任意范围访问并修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>


void Function()
{
static int i = 0;
i++;
std::cout << i << std::endl;


}


int main()
{
Function();

Function();
Function();
Function();
Function();
std::cin.get();

}

静态局部变量生存期为整个程序的生存期,但作用域被限定在函数体内


C++ Primer GCC编译器使用

创建C++文件

我们先在ubuntu创建文件夹C++,然后使用vim新建helloworld.cpp

1
2
3
4
5
6
ls
mkdir C++
ls
vi helloworld.cpp
i
wq
  vim: i 进入读写模式     w 保存文件       q 退出文件   

  ubuntu:mkdir 创建目录   ls显示当前目录下所有文件

helloworld代码

1
2
3
4
5
6
7
8
#include <iostream>

int main()
{
std::cout << "Hello World!" << std::endl;
return 0;

}

编译运行

ubuntu自带g++编译器
使用指令

1
g++ -v 

即可查看对应版本

1
g++ helloworld.cpp -o helloworld

使用g++编译器编译,-o自定义可执行文件名
执行

1
./helloworld


C++ 类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#define LOG(x) std::cout << x << std::endl


class Player
{
public:
int x, y;
int speed;
void Move(int xa, int ya)
{
x += xa * speed;
y += ya * speed;
}

};

//void Move(Player& player,int xa, int ya)
//{
// player.x += xa * player.speed;
// player.y += ya * player.speed;
//}

int main()
{
Player player1;
player1.x = 5;
player1.y = 5;
player1.speed= 5;
//Move(player1, 1, -1);
player1.Move(1, -1);
std::cin.get();


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>

//日志输出类
class Log
{
public:
const int LogLevelError = 0;
const int LogLevelWarning = 1;
const int LogLevelInfo = 2;
private:
int m_LogLevel = LogLevelInfo; //默认日志输出模式

public:
void SetLevel(int level)
{
m_LogLevel = level;
}
void Error(const char* message)
{
if (m_LogLevel >= LogLevelError)
std::cout << "[ERROR]: " << message << std::endl;
}
void Warn(const char* message)
{
if (m_LogLevel >= LogLevelWarning)
std::cout << "[WARNING]: " << message << std::endl;
}
void Info(const char* message)
{
if (m_LogLevel >= LogLevelInfo)
std::cout << "[INFO]: " << message << std::endl;
}
};


int main() {

Log log;
log.SetLevel(log.LogLevelWarning); //日志等级设置
log.Warn("Hello!");
log.Error("Hello!");
log.Info("hello!");
std::cin.get();


}


使用枚举进行了优化

继承



C++ 构造函数和析构函数

构造函数

一个类的对象被创建的时候,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作。因此,构造函数的核心作用就是,*初始化对象的数据成员</font>

2、构造函数的特点
(1)名字与类名相同,可以有参数,但是不能有返回值(连void也不行)。

(2)构造函数是在实例化对象时自动执行的,不需要手动调用。

(3)作用是对对象进行初始化工作,如给成员变量赋值等。

(4)如果定义类时没有写构造函数,系统会生成一个默认的无参构造函数,默认构造函数没有参数,不做任何工作。

(5)如果定义了构造函数,系统不再生成默认的无参构造函数.

(6)对象生成时构造函数自动调用,对象一旦生成,不能在其上再次执行构造函数
一个类可以有多个构造函数,为重载关系

默认构造函数

如果创建一个类,没有写任何构造函数,则系统会自动生成默认的无参构造函数,且此函数为空。

但只要有下面某一种构造函数,系统就不会再自动生成这样一个默认的构造函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

class Entity
{
public:
float X, Y;
Entity() {

}//默认构造方法什么都不做

void Print() {
std::cout << X << ", " << Y << std::endl;
}
};


int main()
{
Entity e;

e.Print();
std::cin.get();

}


通过间接调用Print函数输出了未初始化的X和Y

C++必须手动初始化变量

无参构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
#include <iostream>

class Entity
{
public:
float X, Y;
Entity() {
X = 0.0f;
Y = 0.0f;
}//无参构造方法

void Print() {
std::cout << X << ", " << Y << std::endl;
}
};


int main()
{
Entity e;

e.Print();
std::cin.get();

}

通过无参构造函数初始化变量X,Y

一般构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>

class Entity
{
public:
float X, Y;
// Entity() {
// X = 0.0f;
// Y = 0.0f;
// }

Entity(float x ,float y) {
X = x;
Y = y;
}


void Print() {
std::cout << X << ", " << Y << std::endl;
}
};


int main()
{
// Entity e;
// e.Print();
Entity e1(11.4f,5.14f);
e1.Print();
std::cin.get();

}

复制构造函数

待续ing

构造方法的重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>

class Entity
{
public:
float X, Y;
Entity() {
X = 0.0f;
Y = 0.0f;
}

Entity(float x ,float y) {
X = x;
Y = y;
}


void Print() {
std::cout << X << ", " << Y << std::endl;
}
};


int main()
{
Entity e;
e.Print();
Entity e1(11.4f,5.14f);
e1.Print();
std::cin.get();

}

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。

析构函数

析构函数于构造函数相对应,构造函数是对象创建的时候自动调用的,而析构函数就是对象在销毁的时候自动调用的的

特点:

1)构造函数可以有多个来构成重载,但析构函数只能有一个,不能构成重载

2)构造函数可以有参数,但析构函数不能有参数

3)与构造函数相同的是,如果我们没有显式的写出析构函数,那么编译器也会自动的给我们加上一个析构函数,什么都不做;如果我们显式的写了析构函数,那么将会覆盖默认的析构函数

4)在主函数中,析构函数的执行在return语句之前,这也说明主函数结束的标志是return,return执行完后主函数也就执行完了,就算return后面还有其他的语句,也不会执行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//构造函数与析构函数
#include <iostream>

class Entity
{
public:
float X, Y;


Entity() {
X = 0.0f;
Y = 0.0f;
std::cout << "Created Entity!" << std::endl;

}
~Entity() {
std::cout << "Destroyed Entity!" << std::endl;

}


void Print() {
std::cout << X << ", " << Y << std::endl;
}
};

void Function() {
Entity e;
e.Print();
e.~Entity(); //手动调用析构函数,函数并未结束
}


int main()
{

Function();
std::cin.get();

}

析构函数-CSDN博客

C++构造函数的三种写法 - 知乎 (zhihu.com)

C++构造函数的各种用法全面解析(C++初学面向对象编程)_c++ 构造函数_Chung丶无际鹰的博客-CSDN博客


C++ 枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>


enum Example : unsigned char //必须为整型
{
A = 5, B, C //此时B、C值为6,7,依次++
};


int main()
{
Example value = B;

if (value == 6)
{
std::cout << "hello" << std::endl;
}


std::cin.get();

}

对class学习中的log类进行修改CppClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


#include <iostream>

//日志输出类
class Log
{
public:
enum Level
{
LevelError = 0, LevelWarning, LevelInfo //LevelError = 0, LevelWarning = 1, LevelInfo = 2
};

//const int LogLevelError = 0;
//const int LogLevelWarning = 1;
//const int LogLevelInfo = 2;
private:
int m_LogLevel = LevelInfo; //默认日志输出模式
public:
void SetLevel(int level)
{
m_LogLevel = level;
}
void Error(const char* message)
{
if (m_LogLevel >= LevelError)
std::cout << "[ERROR]: " << message << std::endl;
}
void Warn(const char* message)
{
if (m_LogLevel >= LevelWarning)
std::cout << "[WARNING]: " << message << std::endl;
}
void Info(const char* message)
{
if (m_LogLevel >= LevelInfo)
std::cout << "[INFO]: " << message << std::endl;
}
};


int main() {

Log log;
//log.SetLevel(log.LevelInfo); //日志等级设置
log.SetLevel(Log::LevelError); //有个枚举数叫LevelError在log这个类的命名空间

log.Warn("Hello!");
log.Error("Hello!");
log.Info("hello!");
std::cin.get();


}



C++ 学习笔记

  • ctrl + F7 build

  • 编译器为每个C++源文件(.cpp , 翻译单元)编译成目标文件(.obj)

  • 翻译单元指C编译器产生目标文件(object file)的最终输入

1 简述

在C语言术语中, 翻译单元指C编译器产生目标文件(object file)的最终输入。在非正式使用情况下,翻译单元也叫编译单元。一个编译单元大致由一个经过C预处理器处理过的源文件组成,意味着由#include指令列出的头文件会被正确的包含进来,由#ifdef指令包含的代码会被包含进来,定义的宏会被展开。

2 上下文

由单元组成的C程序叫源文件(或者叫预处理文件),源文件除了源代码以外,还包括C预处理指令。一个源文件经过预处理器处理后的输出叫做翻译单元。

预处理主要包括将一个源文件中由#include指令声明的文件(通常是头文件,也可能是其它源文件)递归地替换,产生的结果是一个预处理翻译单元。接下来包括对#define指令进行宏展开,对#ifdef指令进行条件编译等等; 这一步便将预处理翻译单元转换成一个翻译单元。编译器从翻译单元产生一个目标文件,目标文件经过后续处理后链接(可能需要其它目标文件)成一个可执行程序。

需要注意的是预处理器是语言无关的,只是一个词法处理器,只在词法分析级别,它并不做语法分析,所以它不能处理具体的C语法。编译单元做为编译器的输入,它将不会看到任何预处理指令,因为在编译之前预处理指令已经被预处理器处理了。一个翻译单元根本上是基于一个文件,实际输入编译器的源代码可能和程序员所看到的大不一样,特别是递归包含的头文件。

3 范围

翻译单元定义了一个范围,大致是文件范围,功能上类似于模块范围;在C术语中称为内部连接,内部连接是C语言中两种连接方式之一。在函数块外声明的名字(函数和变量)仅对该翻译单元可见,称为内部连接),内部连接对链接器不可见。如果名字对其它翻译单元可见,称为外部连接),外部连接对链接器可见。

C语言没有模块的概念。但是单独的目标文件(翻译单元产生的目标文件)功能也像一个独立的模块,如果一个源文件没有包含其它源文件,内部连接(翻译单元范围)可能被认为是包括所有头文件的文件范围。

4 代码组织

大部分工程的代码都是保存在以.c为后缀(c++用.cpp, .c++, 或 .cc,通常用.cpp)的文件中。被包含的文件一般以.h为后缀(c++用.hpp或.hh, 在c++中通常用.h比较多),为了避免多个源文件包含头文件产生的名字冲突,头文件中一般不包含函数或变量的定义。头文件可以被其它头文件包含。在项目中,.c文件至少包含一个头文件是标准做法。

定于float浮点数需加入f才能转化为float类型 2.3f

f9 设置断点

strcut和class的区别 (唯一区别:可见性)

默认的继承访问权。class默认的是private,strcut默认的是public。

{

结构体用来表示一些数据

类用来表示有大量功能的 的需要继承的

}//不同人看法不同

static、extern关键词

static

类外面的static,意味着你声明为satatic的符号,连接将只是在内部,只能对你定义它的翻译单元可见

使用static修饰的静态函数或静态变量只会在它被声明的C++文件中被“看到”

s_Var常用这种方式表示静态变量

extern意味着它会在外部翻译单元中寻找s_Var变量

尽量使用局部变量而不是全局变量,全局变量容易出现bug

聚合类

  1. 无自定义构造函数;
  2. 非静态数据成员没有大括号或等号初始化器,即类内没有初始值;
  3. 无私有或保护的非静态成员;
  4. 无基类和虚函数。

聚合类的的主要特性是可以使用{}符号像数组一样进行初始化。

类实例会创建一个命名空间

在 C++ 中,this 指针是一个特殊的指针,它指向当前对象的实例。

每个非静态方法总是获得当前类的一个实例作为参数

静态方法实际上是在类实例的命名空间外的

静态方法没有类实例(没有this指针)

意味着你可以在没有创建类的实例的情况下直接调用该方法

静态方法内部,你不能直接访问或修改实例变量,也不能调用非静态的成员函数。

但可以通过传入对象作为参数访问(非静态方法自动引入)

static void Print () //静态方法

static void Print(Entity e) //非静态方法实际编译时的样子

静态方法与在类外部编写方法相同

类对象构造时,会隐含一个this指针参数,已保存构造中new出的空间

禁止返回局部栈引用或指针

C++枚举 (enumeration)