C++学习

一、指针

1、普通指针

不管指向什么类型的指针,其本质就是一个整数。

指针的创建:

int* pointer=NULL;
int* a,*b;

获取变量地址: 

int a;
int* pointer=&a;

 修改指针所指向的变量值:

*pointer=1;

2、智能指针

 实现自动化的释放内存。

(1)unique_ptr作用域指针

当超出作用域之后内存便会被释放。不能被复制。

#include <iostream>
#include <memory>
class Entity
{
public:
    int x, y;
public:
    Entity(int x_value,int y_value)
        :x(x_value),y(y_value)
    {
        std::cout << "create objection" << std::endl;
    }
    ~Entity()
    {
        std::cout << "destory objection" << std::endl;
    }
};

int main()
{
    {
        std::unique_ptr<Entity> entity=std::make_unique<Entity>(1,1);
    }//执行到这里时内存释放
}
(2)shared_ptr计数指针 

可以被复制,当作用域内所有引用消失后释放内存。

(3)weak_ptr弱指针

3、函数指针

指向函数的指针,但指针的类型比较奇怪,一般用auto或者typedef来替换。

(1) 使用auto替换
//使用auto
#include <iostream>
void print()
{
	std::cout << "hello world" << std::endl;
}

int main()
{
	auto function = print;//auto简化类型名
	function();
}
 (2) 使用typedef替换
//使用typedef
int main()
{
	typedef void(*function)();
	function a= print;
	a();
}
(3) lambda

一种匿名函数,可以使用在有函数指针的地方。

#include <iostream>
#include <vector>
#include <algorithm>
void ForEach(const std::vector<int>& values, void(*func)(int))
{
	for (int value : values)
	{
		func(value);
	}
}
void print(int value)
{
	std::cout << "value:"<<value << std::endl;
}

int main()
{
	std::vector<int> values= {1, 2, 3, 4, 5};
	ForEach(values, [](int value) {std::cout << "value:" << value << std::endl; });
	std::cin.get();
}

二、引用

引用:可以创建引用“变量”,但必须引用现有的值(不赋初值会报错),这个“变量”并不会分配内存。

int a;
int& b=a;

引用其实就是指针的一种修饰用法,使得代码更加简洁,更像是为变量创建了一个别名,引用就是内容本身。

指针用法:改变函数中参数的值

#include <iostream>
int increase(int* value)
{
    (*value)++;
}
int main()
{
    int a=1;
    increase(&a);
    std::cout<<a<<std::endl;
}

引用用法:改变函数中参数的值

#include <iostream>
int increase(int& value)
{
    value++;
}
int main()
{
    int a=1;
    increase(a);
    std::cout<<a<<std::endl;
}

三、类和对象&结构体 

1、类

包含一系列变量和函数,变量和函数默认是私有的。

class Player
{
public:
    int x, y;
    void move(int add)
    {
        x += add;
    }
};

创建对象——默认在栈上分配

Player player;

2、可见性 

protected:
private:
public:

protected:

在类和子类中可以访问。 

private:

只有在类中才能访问(子类中也不能访问,除了friend)。

public:

任意地方都可以访问。

3、初始化成员列表

类似于构造函数,对类中的变量进行初始化——按照变量声明顺序进行初始化。

class Player
{
protected:
    int x, y;
public:
    Player()
        :x(1),y(1)
    {
    }
    void get()
    {

        std::cout << x << std::endl;
    }
};

4、 隐式转化

隐式转化只能进行一次,为了简化代码。

class Entity
{
private:
    int x,y;
public:
    Entity()
        :x(1),y(1)
    {

    }
    Entity(int value_X)
    {
        x=value_x;
    }
}
//创建对象
Entity e=2;

5、构造函数和析构函数 

(1)构造函数

初始化对象。

class Player
{
public:
    int x, y;
    Player()
    {
        x = 0;
        y = 0;
    }
    Player(int value_x, int value_y)
    {
        x = value_x;
        y = value_y;
    }
};
(2)析构函数 

在程序结束时销毁对象。

class Player
{
public:
    int x, y;
    Player()
    {
        x = 0;
        y = 0;
    }
    Player(int value_x, int value_y)
    {
        x = value_x;
        y = value_y;
    }
    ~Player
    {
    }
};

6、复制和拷贝构造函数

 复制会带来时间消耗,有代价,尽量减少不必要的复制。

(1)类的复制

对于类中的指针成员,进行的是浅复制,只复制了地址。

//代码会报错,因为对象的复制是浅复制,会两次释放相同的内存,导致程序错误。
#include <iostream>
#include <String>

class String
{
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string)
	{
		m_Size = strlen(string);
		m_Buffer = new char[m_Size+1];
		memcpy(m_Buffer,string,m_Size+1);
	}
	~String()
	{
		delete[] m_Buffer;
	}
	friend std::ostream& operator<<(std::ostream& stream, const String& string);
	char& operator[](unsigned int index)
	{
		return m_Buffer[index];
	}
};
std::ostream& operator<<(std::ostream& stream, const String& string)
{
	stream << string.m_Buffer;
	return stream;
}

int main()
{
	String string = "xyy";
	String second = string;
	std::cout << string << std::endl;
}
(2)拷贝构造函数

深度地复制,相当于创建一个新对象,对于指针成员会单独分配地址。

#include <iostream>
#include <String>

class String
{
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string)
	{
		m_Size = strlen(string);
		m_Buffer = new char[m_Size+1];
		memcpy(m_Buffer,string,m_Size+1);
	}
//拷贝构造函数
	String(const String& other)
		:m_Size(other.m_Size)
	{
		m_Buffer = new char[m_Size+1];
		memcpy(m_Buffer,other.m_Buffer,m_Size+1);
	}
	~String()
	{
		delete[] m_Buffer;
	}
	friend std::ostream& operator<<(std::ostream& stream, const String& string);
	char& operator[](unsigned int index)
	{
		return m_Buffer[index];
	}
};
std::ostream& operator<<(std::ostream& stream, const String& string)
{
	stream << string.m_Buffer;
	return stream;
}

int main()
{
	String string = "xyy";
	String second = string;
	std::cout << string << std::endl;
}
(3)对象作为函数参数时

 当对象作为函数参数传递时会进行一次复制。通常用const type &去传递对象不会复制对象。

//用const引用去传递对象不会带来复制
void print(const String& string)
{
    std::cout<<string<<std::endl;
}

7、结构体

包含一系列变量和函数,变量和函数是公有的。

struct operate
{
    int x=1, y;
    void move(int add)
    {
        x += add;
    }
};

创建结构体: 

operate operate_1;

 四、关键字

1、static

(1)不同文件中的static:

相当于声明局部变量或函数。

log.cpp中

static int s_value=5;

main.cpp中

int s_vlaue;
(2)类中的static:

类中的static变量作用于所有对象,所有创建的对象共享。

class Player
{
    static int x,y;
    static int move(int speed)
    {
        x=x+speed;
    }
}
(3)作用域和生命周期 :

static变量的生命周期是整个程序,作用域是声明的函数或者文件。

2、const

(1)修饰常规数据类型

修饰一些常量,相对于给出承诺这些量是不变的——一定要初始化。

const int a=5;
(2)修饰指针 

在*号之前——不能修改指针指向的内容。

const int* a= new int;
int const* a= new int;

在*号之后——不能修改指针的值。

int* const a= new int;
(3)修饰类 

对类中方法进行修饰——把方法变为只读,不能修改类中数据。

class Entity
{
private:
    int a;
public:
    int getx() const
    {
        return a;
    }
}

3、mutable 

一般用在类中声明的const方法要调用一些参数,可以在变量前加上mutable。

class Player
{
private:
    int mutable x, y;
public:
    void get() const
    {
        x = 1;
        std::cout << x << std::endl;
    }
};

4、new & delete

封装了c语言中的malloc和free,在堆中分配内存。

int* a = new int;
delete a;
int* b= new int[5];
delete[] b;

5、explicit

 使得构造函数不能使用隐式转化。

class Entity
{
private:
    int x,y;
public:
    Entity()
        :x(1),y(1)
    {

    }
    explicit Entity(int value_X)
    {
        x=value_x;
    }
}
//创建对象
Entity e(2);

6、this

 指向当前对象的指针,不能修改其指针的值。

//用法一---赋值给当前对象
class Entity
{
private:
    int x, y;
public:
    Entity(int x,int y)
    {
        this->x = x;
        this->y = y;
    }
};
//用法二---在函数中传递当前对象作为参数
void printEntity(Entity& e)
{
    std::cout<<e.x<<std::endl;
}
class Entity
{
public:
    int x, y;
public:
    Entity(int x,int y)
    {
        this->x = x;
        this->y = y;
    }
    printEntity(this);
};

7、inline

内联函数标识符——相当于宏定义。每当程序中出现对该函数的调用时,C++编译器使用函数体中的代码插入到调用该函数的语句之处,同时使用实参代替形参,以便在程序运行时不再进行函数调用。引入内联函数主要是为了消除调用函数时的系统开销,以提高运行速度。

  • 内联函数在第一次被调用之前必须进行完整的定义,否则编译器将无法知道应该插入什么代码
  • 在内联函数体内一般不能含有复杂的控制语句,如for语句和switch语句等
  • 使用内联函数是一种空间换时间的措施,若内联函数较长,较复杂且调用较为频繁时不建议使用
#include <iostream>

inline int add(int x, int y)
{
	return x + y;
}
int main()
{
	std::cout << add(1, 1) << std::endl;
}

8、auto 

自动推断变量类型。

auto a = 1;//int
auto a = 1L;//long
auto a = 1.1f;//float

 其他简化类型名的方式

using newtype=std::string;
typedef std::string newtype;

9、namespace

 命名空间——为了避免命名冲突。

namespace apple {
	void print();
}
namespace orange {
	void print();
}

五、枚举

枚举:定义一系列的整数。

enum level
{
    low,mid,high
};

默认第一个变量为0,后续变量递增。

为了节省内存可以指定enum的类型,不能用float和double,因为enum数为整数。

enum level :char
{
    one,two,three
};

六、构造函数&析构函数

1、构造函数

初始化对象。

class Player
{
public:
    int x, y;
    Player()
    {
        x = 0;
        y = 0;
    }
    Player(int value_x, int value_y)
    {
        x = value_x;
        y = value_y;
    }
};

 2、析构函数

在程序结束时销毁对象。

class Player
{
public:
    int x, y;
    Player()
    {
        x = 0;
        y = 0;
    }
    Player(int value_x, int value_y)
    {
        x = value_x;
        y = value_y;
    }
    ~Player
    {
    }
};

七、 继承

继承:实现对其他类的复用。

class object : public Player
{
public:
    int a, b;
};

八、虚函数&纯虚函数

1、虚函数

子类对父类方法进行修改。

class Player
{
public:
    int x, y;
    Player()
    {
        x = 0;
        y = 0;
    }
    Player(int value_x, int value_y)
    {
        x = value_x;
        y = value_y;
    }
    virtual void move(int speed)
    {
        x = x + speed;
        y = y + speed;
    }
};
class object : public Player
{
public:
    void move(int speed) override
    {
        x = x + 2 * speed;
        y = y + 2 * speed;
    }
};

2、纯虚函数

在父类中对方法不做定义,提供了类似接口的方式,方便在子类中编写方法——方法必须在子类中实现,同时不能用有纯虚函数的类创建对象。

class Player
{
public:
    int x, y;
    Player()
    {
        x = 0;
        y = 0;
    }
    Player(int value_x, int value_y)
    {
        x = value_x;
        y = value_y;
    }
    virtual void move(int speed)=0;

};
class object : public Player
{
public:
    void move(int speed) override
    {
        x = x + 2 * speed;
        y = y + 2 * speed;
    }
};

九、数组、字符串

1、数组创建

int a[5];
//---//
#include <array>
std::array<int,5> a;

2、 字符串创建

const char* c = "1234";
//---//
#include <string>
std::string a = "1234";

十、运算符和重载

1、运算符意义

运算符本质就是函数。

c=a+b;
c=a/b;
c=a*b;
c=a\b;
c=a<<b;

2、 ->操作符

简化指针运算符操作。

struct vector2
{
    float x;
    float y;
};

int main()
{
    vector2 v = {1,1};
    vector2* e=new vector2();
    e = &v;
    std::cout<<e->x<<std::endl;
}

3、 重载

在程序中定义或修改运算符的行为(尽量少用,会导致程序难以阅读)。

//定义运算变量形式---向量相加
struct vector2
{
    float x, y;
};
//定义函数
vector2 add(vector2 a, vector2 b)
{
    vector2 result;
    result.x = a.x + b.x;
    result.y = a.y + b.y;
    return result;
}
//运算符重载
vector2 operator+(vector2 a, vector2 b)
{
    return add(a,b);
}

十一、外部库使用

1、静态链接

2、动态链接

十二、模板

让编译器帮你写代码。

1、函数中使用

对函数参数类型进行替换。

//模板只有在调用时才会编译
//相当于做填空进行替换
template<typename T>
print(T value)
{
    std::cout<<value<<std::endl;
}
int main()
{
    print(5);
    print("hello");
}

2、类中使用 

指定数组大小

template<int N>
class array
{
private:
    int a[N];
public:
    int Getsize() const
    {
        return N;
    }
};
int main()
{
    array<5> a;//指定N的大小
}

十三、宏定义

十四、多线程

基本用法

#include <iostream>
#include <thread>

static bool s_finished = 0;
void DoWork()
{
	std::cout << "Working" << std::endl;
}

int main()
{
	std::thread worker(DoWork);
	std::cin.get();
	s_finished = 1;
	worker.join();
	std::cin.get();
}

十五、计时

#include <iostream>
#include <chrono>
#include <thread>

int main()
{
	using namespace std::literals::chrono_literals;
	auto start = std::chrono::high_resolution_clock::now();
	std::this_thread::sleep_for(1s);
	auto end = std::chrono::high_resolution_clock::now();

	std::chrono::duration<float> duration = end - start;
	std::cout << duration.count() << std::endl;
	std::cin.get();
}

利用类的特性构造函数和析构函数——作用域结束后调用析构函数,来实现计时。 

class Timer
{
	std::chrono::time_point<std::chrono::steady_clock> start, end;
	std::chrono::duration<float> duration;
	Timer()
	{
		start = std::chrono::high_resolution_clock::now();
	}
	~Timer()
	{
		end = std::chrono::high_resolution_clock::now();
		duration = end - start;

		std::cout << "Timer:" << duration.count() << std::endl;
	}
};

十六、函数

1、函数返回多个值

2、函数指针

void helloworld()
{
    std::cout << "hello world" << std::endl;
}

int main()
{
    /*函数指针用法一*/
    void(*function_1)();
    function_1 = helloworld;//隐式转化=&helloworld
    function_1();
    /*函数指针用法二*/
    typedef void(*hellofunction)();
    hellofunction function_2 = helloworld;
    function_2();
    std::cin.get();
}

  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值