C++ 语言指南

命名规则
  • 以两个下划线或者一个下划线和大写字母开头的名称被保留
  • 以一个下划线开头的名称被保留
命名空间
  • #include “ custom.h ”包含某个自定义的库,使用双引号外加.h后缀
  • #include <iostream>包含某个标准库, 使用尖括号
  • using namespace std 使用某个标准空间,可以在函数内声明【仅在该函数内有效】,也可以在全局声明
数据
  • 把int 类型的数字赋值给布尔的时候,大于0为true,小于等于0为false

  • 把布尔赋给int类型的时候,true为1,false为0

  • int short long long

  • float double long double

  • char 可以直接赋给int,int也可以赋给char

  • C++的取模运算必须都是整数类型,不支持浮点数。

  • 强制类型转换int( ) (int) k

  • auto关键字可以自动推断类型 auto a = 12;.缺点,浮点值默认类型是double类型,可能自动推导可预期不符。

  • 数组声明int num[] = {1,2,3}; int num2[3] = {1,2};在C++11中可以去掉等号int num3[]{1,2,3}数组的声明和多数据初始化必须在同一行,否则只能单个赋值

  • 在C++中有两种风格的字符串,一种是C语言风格

    • 用字符数组代替字符串char name[] = { 'a','p','p','l','e' ,'\0'}但是这种需要把字符串的每个字符列出来,还需要加上空字符‘\0’
    • 用字符串直接赋值char[] name = "apple" 会自动加上空字符和填充数组
    • strlen(name)会获取字符串的长度,不包括‘\0’ 空字符,但是数组的长度是包括空字符的
    • 可以多行字符串,自动进行拼接,char name[] = " my name is apple" "well , you do"
  • 另一种是C++的类库风格,使用string需要引入#inclue<string>的库

    • 字符串可以相加 string str1,str2; str1+=str2
    • 获取字符串的长度str1.size()
    • 获取用户输入getline(cin, str1);
  • cin的问题,cin是以空格符,制表符, 回车结束的,但是输入的字符串中可能包含空格符 改用cin.getline()获取一行

	cout << "请输入名字";
	char name[30];
	cin>>name;
	cout << "请输入你的食物";
	char food[12];
	cin >> food;

	cout << name << "喜欢吃" << food;
指针
  • 指针在使用之前必须初始化
  • 指针可以赋空值,有三种方法int* c = 0; float* d = NULL; float* k = nullptr;
  • 空类型指针可以接受任意类型的数据的指针,但是取值时需要强转int a = 10; void* ptr = &a; cout<< *(int*)ptr 最后输出10
  • 可以为基础类型分配空间, int* p = new int; *p = 10; delete p;
数组
  • 创建数组的三种方式
    • 普通方式 int num[] = {1,2,3},数组和数组之间无法赋值
    • 通过指针分配空间方式int* numPtr = new int[3]{1,2,3}; delete[] numPtr;
    • 但凡是通过new分配的空间都需要在使用完毕之后通过delete释放
    • 通过模板类, 引用#include <array>,第一个参数是类型,第二个参数数组长度,array<int, 3> numModel = {1,2,3}
    • 模板类创建的数组之间可以互相赋值array<int, 4> num5 = { 1,6,7,8 }; array<int, 4> num6 = { 0,7,9,4 }; num5 = num6;
遍历数组的方式
	array<int, 3> num = { 1,2,3 };
	for(int& i:num)
	{
		i = 11;   //支持读写
	}
	for (int i : num) {  //只支持读取
	
		cout << i;
	}
函数和数组
  • 存在局部静态变量,和局部变量的区别在于,一个在程序终止的时候销毁,一个在函数运行完的时候销毁
  • 函数需要先声明后使用。【这里我比较疑惑,因为预先声明是很麻烦的,完全可以用预编译来解决】
引用类型
  • int&定义引用类型,两个变量指向同一块内存区域,相当于获取某块内存区域的地址然后赋给对应指针 int a = 10; int& b =a;
  • int& 类型可以赋值给int&,两者指向同一块内存区域,也可以赋值给int类型,但只是把数据拷贝一份赋给int数据而已
  • 指针类型的引用
const
  • const int * p 可以修改指针p的值,但是不能修改p指向内存区域的值
  • int* p 因为p可以修改其内存区域的值,因此不能这样const int b; p = &b;会报错
  • int * const不可以修改指针p的值,但是可以修改p指向内存区域的值,因此不能这样const int b; p = &b;会报错
  • const int& b 可以接收intconst int 的值,b的值无法改变
  • int& b只可以接受int的值
默认参数
  • 在C++中也存在默认参数,需要在函数声明中标明
int Add(int a, int b =100);
int Add(int a, int b) {
	return a + b;
}
内联函数
  • 将对应的函数调用替换为函数的代码,为了加快运行速度
  • 但是这样会增大内存
  • 在函数声明或函数定义前面加上关键字inline
  • 注意内联函数不能递归;
常量表达式
ConstExpr int AddTen(int a){
	return a+10;
}
  • 默认是内联函数
  • 可以递归, 参数和返回类型都必须是字面值类型。
  • 如果传入的是常量,会在编译期自动计算出结果,如果是变量,会在运行期计算出结果
函数指针
  • 函数指针指向的是函数而非对象
  • 想要声明一个函数指针,只需要用指针替换函数名即可
  • 可以用typedef定义一个函数指针类型
  • 可以返回一个函数指针,也可以当做形参传递
bool lengthCompare(const string&, const string&); //函数
bool (*pf)(const string&, const string&); //函数指针

int AddPf(int a, int b, int (*sd)(int, int)) {
	return sd(a, b);
}

typedef int(*len) (int, int);
int main()
{
	len ptr = Add;
	int result = AddPf(12, 23, ptr);
	cout << result;
}
申请内存
  • 申请内存不一定能成功
  • 所以在申请之后要判断是否为null
  • 此外还要将对应指针赋值为null 这样就可以避免重复释放
int*p = new int[100];
if(p==Null){
	//内存分配失败
}
p = Null;
定义类
  • 类内定义
  • 在类定义内的成员函数会隐式的编译成内联函数;
  • 内联函数inline是编译建议,编译器会自己根据函数的复杂程度自己决定是否内联
  • 类外定义分为同文件类外定义和分文件类外定义【有经验都是分开】
    • 同文件即将定义和函数写在一个cpp中,函数体在外,需要标注类名前缀
    • 分文件定义即将定义写在.h头文件中,将函数体写在另外的.cpp文件中,.cpp中需要引用其头文件,同样需要标注前缀
  • 初始化列表Student() :age(35),name("ka"){}
    • 初始化列表先于构造函数执行
    • 初始化列表只能用于构造函数
    • 初始化列表可以同时初始化多个数据成员
    • 必要性,这样就可以修改const值
class Circle
{
	
private:
	const double dPi;
public:
	void Print(Student& stu);
	Circle():dPi(3.14) {   }
};
  • 拷贝构造函数 当一个对象发生拷贝的时候,该函数就会被调用,编译器会提供默认实现Student( const Student& copy).
    • void PrintStudent(Student stu) 作为参数传递的时候发生拷贝
    • Student s1; Student s2(s1); Student s3 = s1; 发生拷贝
void Test(Student& s1) {}
 
int main()
{

	//Student* s1 = new Student("贾亚杰", 45, 12, 23, 45, 20141026);
	Student s1("不流人", 46, 12, 23, 45, 20141027);
	Student s2 = s1;
	Student s3(s1);
	Test(s1);
}
  • 分文件 类外定义
  • 分为两个部分,类的声明.h部分和函数实现部分.cpp
  • .h部分
#pragma once
#include <string>

using namespace std;

class Student
{


private:
	string name;
	float mathScore;
	float chineseScore;
	float englishScore;
	float physicsScore;
	int id;

public:
	Student(string nameM, float mathScoreM, float chineseScoreM, float englishScoreM, float physicsScoreM, int idM);
	~Student();
	float GetAverage();
	string GetName();
	float GetSumScore();
	bool CompareScore(Student& other);
};
  • .cpp部分
#include "Student.h"
#include <iostream>



Student::Student(string nameM, float mathScoreM, float chineseScoreM, float englishScoreM, float physicsScoreM, int idM)
{
	name = nameM;
	mathScore = mathScoreM;
	chineseScore = chineseScoreM;
	englishScore = englishScoreM;
	physicsScore = physicsScoreM;
	id = idM;
}

Student::~Student()
{
	cout << "销毁" << this->name;
}

float Student::GetAverage()
{
	return this->GetSumScore() / 4;
}

string Student::GetName()
{
	return name;
}

float Student::GetSumScore()
{
	return mathScore + chineseScore + englishScore + physicsScore;
}

bool Student::CompareScore(Student& other)
{
	return this->GetAverage() > other.GetAverage();
}

实例化对象
  • 从栈中实例化对象,当函数运行结束后就会自动释放
  • 从堆中实例化对象通过new,当不再使用的时候要用delete进行释放
  • 析构函数
  • 在对象被销毁时候被调用的函数,可以在这个函数中做一些释放内存的操作
  • 编译器会自动添加~Student(){ }
  • 通过拷贝构造函数产生的对象在释放的时候也会调用
	Student* s1 = new Student("贾亚杰", 45, 12, 23, 45, 20141026);
	Student s2("不流人", 46, 12, 23, 45, 20141027);

	cout << s1->GetName() << s1->GetAverage();
	cout << s2.GetName() << s2.GetAverage();
	cout << s1->GetName() << "比" << s2.GetName() << "大" << s1->CompareScore(s2);

	delete s1; //当s1被删除的时候,析构函数就会被调用
	s1 = NULL;
  • 创建类的对象数组时候,这个类必须有默认构造函数,因为初始化对象的时候,会首先使用默认构造函数创建数组元素
	Student stus[5] = {};
	stus[0] = Student("贾杰", 45, 12, 23, 45, 20141026);
	stus[1] = Student("贾发", 45, 12, 23, 45, 20141027);
	stus[2] = Student("贾亚", 45, 12, 23, 45, 20141028);
	for (int i = 0; i < size(stus); i++)
	{
		cout << stus[i].GetName();
	}
对象成员
class Line
{
	Point end;
	Point start;

public:
	Line(float sx, float sy, float ex, float ey);
};

int main(){

	Line* line = new Line(1, 2, 3, 4);
	delete line;
	//创建点34创建点12创建line销毁line12被销毁34被销毁 其顺序
}
  • 在实例化的时候首先实例化end,其次实例化start,最后实例化Line
  • 对象成员指针
#include "Line.h"
#include <iostream>
using namespace std;

Line::Line(float sx, float sy, float ex, float ey)
{
	start = new Point(sx, sy);
	end = new Point(ex, ey);

	cout << "创建line" << endl;
}

Line::~Line()
{
	cout << "销毁line" << endl;

	delete start;
	start = NULL;

	delete end;
	end = NULL;

	
}
  • 常对象成员
  • 用const修饰的对象成员,不能改变,只能在初始化列表中初始化
  • 常成员函数
  • 用const修饰的成员函数,不允许改变对象自身的值,因为const被隐士的加到this指针前面
 	void Student::GetName(){  }
 	//在编译时会隐式的添加 this指针
 	void GetName(Student* this)
 	//用const修饰的成员函数
 	void Student::GetName() const {  }
 	//在编译时会隐式的添加
 	void GetName(const Student* this){}
 	//因为this指针被const修改,所以无法通过this来修改数据
	
	void Student::GetName(){  }     //两者互为重载,那么如何辨别你调用的是哪一个函数呢
	void Student::GetName() const {  }
	
	const Student good("007"); //通过const修饰的对象称为常对象
	good.GetName();  //通过常对象来调用的函数即为常成员函数
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值