注释:单行//;多行/**/。
右键源文件点击编译生成.obj;右键项目点击生成输出.exe文件
全局变量会默认初始化,局部变量不会初始化。
条件?执行1:执行2
调试输入输出
//输出 std::cout << 输出内容1 << 输出内容2 << ...; std::cerr << "错误信息:" << 变量 << ...; std::clog << "执行到第" << n << "步"; //输入 std::cin >> 变量1 >> 变量2 >> ...;数组扩展vector模板类(还包括array:固定长度),可使数组长度变为动态的,需加头文件#include<vector>
使用:vector<数据类型(如int)> 变量名;初始化:vector<int> a(5,100),五个变量都为100
获取长度.size;添加元素.push_back;
Enum:枚举数据类型
自定义类型别名
typedef int arrayT[5];//arrayT是一个自定义的类型别名,表示长度为5的int数组命名空间
#include <iostream> using namespace std; // 第一个命名空间 namespace first_space{ void func(){ cout << "Inside first_space" << endl; } } // 第二个命名空间 namespace second_space{ void func(){ cout << "Inside second_space" << endl; } } int main () { // 调用第一个命名空间中的函数 first_space::func(); // 调用第二个命名空间中的函数 second_space::func(); return 0; }数组
静态数组
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};动态数组
std::vector<int> vec; // 初始大小为0(空动态数组) vec.push_back(10); // 添加元素10,大小变为1指针
指针:带有*,赋值时使用取地址符号&获取变量的地址给到指针变量,要获取指针指向的变量可以使用*指针名来解指针
定义空指针:int* p=nullptr/NULL/0
指针变量指向常量:const int* p=&pi(指向的数据必须是常量,但指针本事为变量可以指向不同的常量)
常量指针:int* const p=&i(指向的数据需是变量,但指针本事是常量,指定后不可更改,但解引用后可以修改)
for(int num:arr) { cout<<num<<endl; }指针数组、数组指针
指针数组:一个数组,它的所有元素都是相同类型的指针;
int* pa[4];数组指针:一个指针,指向一个数组的指针;
int(* pb)[4];智能指针
std::unique_ptr<T>:独占资源所有权的指针。std::shared_ptr<T>:共享资源所有权的指针。std::weak_ptr<T>:共享资源的观察者,需要和 std::shared_ptr 一起使用,不影响资源的生命周期。
引用(起别名)的用法,可减少数据拷贝
int a = 10; int& ref = a;引用不占内存,可减少数据拷贝,函数形参使用引用的话能够实现对实参的修改
void Sadd(int & p) { p++; } int main() { int x = 1; Sadd(x);}结构体的引用取内部值本写为(*curr).next;可简化为curr->next
使用数组引用作为形参:
void printArray(const int(& arr)[5]) { for (int num:arr) cout<<num<<endl; }static静态对象:离开作用域依然保留, 创建时不做初始化会默认为0值
//显示自身被调用多少次的函数 int callCount() { static int count = O;//只会被调用一次,且变量一直存在 ++count; cout<<"我被调用了”<<count<<”次!"<< endl; return count; }数据结构:数组、结构、类、链表、栈、队列、映射、集合
动态数组:vector容器
#include <vector>//首先需要引入头文件 //创建 std::vector<int> myVector; std::vector<int> myVector(5, 10); // 创建一个包含 5 个整数的 vector,每个值都为 10 std::vector<int> vec2 = {1, 2, 3, 4}; // 初始化一个包含元素的 vector //添加元素 myVector.push_back(7); // 将整数 7 添加到 vector 的末尾 //删除元素 myVector.erase(myVector.begin() + 2); // 删除第三个元素 //迭代访问 for (auto it = myVector.begin(); it != myVector.end(); ++it) { std::cout << *it << " "; } //或者 for (int element : myVector) { std::cout << element << " "; } //并且可以使用嵌套,定义二维容器 vector<vector<int>> outer;函数
不拷贝的函数使用
const string & longStr(const string& str1,const string& str2) { return str1.size()> str2.size() ? str1:str2; }函数返回类型:指向数组的指针
int fun(int x);//普通int返回值函数声明 int(*fun(int x))[5];//返回值类型为数组指针的函数声明 //方法2 typedef int arrayT[5];//arrayT是一个自定义的类型别名,表示长度为5的int数组 arrayT*fun2(int x);//同上 //方法3,尾置返回类型 auto fun3(int x)->int(*)[5]内敛函数:inline关键词,运行效率会更高,会将使用到的函数在当前位置展开,而不会跳转节省函数调用开销(一般在函数频繁调用且函数内部代码很少的情况下使用内联)
函数指针:
int printBig(int a,int b) { return a>b?a:b; } int main() { int(*fp)(int,int)=nullptr;//定义方法:函数返回类型(*指针名称)(参数类型) fp = printBig;//赋值:可直接用函数名赋值或加取地址符 }95-函数指针定义和用法
函数指针作为形参:还可作为函数返回值
面向对象
类
class myClassname//定义一个类,myClassname为类名 { public: int a=0; private: //数据类型分为静态和动态,类中的静态变量只能在类外赋值,静态变量所有对象共用同一个, //静态成员函数只能访问静态变量且不需要对象就可以调用, static int b; } myClassname abc;//创建一个该类型的对象,abc为对象名 //调用类的静态变量或函数可直接访问,访问时使用:: if(myClass::b==0)std::cout << "true"<< " "; //调用类的非静态函数或变量只能通过创建对象访问,访问时使用. if(abc.a==0)std::cout << "true"<< " ";struct或class,struct定义的类默认是公有的,class默认是私有的,其他没区别
访问权限:public、private(只有自身可以访问)、protected(子类中可以访问)
类函数的声明和实现
构造函数:1,在创建对象的时候,自动调用
2,构造函数名和类名一样,没有返回类型声明
析构函数:1,在对象的生命周期结束,自动调用
2,析构函数和类名一样,在前面加一个~
class Stu { Stu()//构造函数会在创建对象时自动调用,可以做一些初始化 { cout<<init<<endl; } ~Stu()//析构函数 { cout<<destory<<endl; } } { Stu stu1,stu2;//先构造的后析构,如同堆栈 }拷贝构造函数:
移动构造函数:
继承
class Dog { private: int m_age; public: int age(); void setAge(int age);//声明 }; int Dog::age()//实现 { return m_age; }多继承
class Animal { public: string name; } class myDog:public Animal,public Dog { string color; }重载
C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
多态
// 基类 Animal class Animal { public: // 虚函数 sound,为不同的动物发声提供接口 virtual void sound() const { cout << "Animal makes a sound" << endl; } }; // 派生类 Dog,继承自 Animal class Dog : public Animal { public: // 重写 sound 方法 void sound() const override { cout << "Dog barks" << endl; } }; // 测试多态 int main() { Animal* animalPtr; // 基类指针 // 创建 Dog 对象,并指向 Animal 指针 animalPtr = new Dog(); animalPtr->sound(); // 调用 Dog 的 sound 方法 delete animalPtr; // 释放内存,调用 Dog 和 Animal 的析构函数 return 0; }虚函数:有关键字virtual修饰的函数为虚函数,只有虚函数可以在子类中重写,其中const表示函数不可修改成员变量
纯虚函数:
- 纯虚函数是没有实现的虚函数,在基类中用 = 0 来声明。
- 纯虚函数表示基类定义了一个接口,但具体实现由派生类负责。
- 纯虚函数使得基类变为抽象类(abstract class),无法实例化。
class Shape { public: virtual int area() = 0; // 纯虚函数,强制子类实现此方法 };虚析构函数
使用说明:
- 基类是抽象类 / 接口类(如
IFlyable),且会被其他类继承; - 代码中存在 “基类指针 / 引用指向派生类对象”,且会通过基类指针
delete对象; - 基类有其他虚函数(如纯虚函数
Fly()),说明这个类设计为 “多态使用”,必须配套虚析构。
反例:如果去掉virtual ~IFlyable() {},运行下面的代码会出现内存泄漏(派生类的析构函数不会被调用)
#include <iostream> using namespace std; // 无虚析构的纯虚类(模拟接口) class IFlyable { public: virtual void Fly() = 0; // 去掉虚析构:vretual ~IFlyable() {} }; // 派生类 class Bird : public IFlyable { public: Bird() { cout << "Bird 构造" << endl; } ~Bird() { cout << "Bird 析构" << endl; } // 派生类析构 void Fly() override { cout << "Bird 飞" << endl; } }; int main() { // 基类指针指向派生类对象(接口的典型用法) IFlyable* fly = new Bird(); fly->Fly(); // 删除基类指针 delete fly; return 0; }Bird 构造 Bird 飞模板
作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。
语法:
template<typename/class T>//声明一个模板,告诉编译器T是一个通用数据类型 void mySwap(T &a,T &b) { T temp =a; a=b; b=temp;} //使用时可以让其自动推导数据类型,也可显式指定类型 mySwap(a,b); mySwamp<int>(a,b);模板函数和普通函数调用规则
1.如果函数模板和普通函数都可以实现,优先调用普通函数
2.可以通过空模板参数列表来强制调用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配,优先调用函数模板
模板具体化
template<class T> bool func(T a,T b)//如果传入自定义数据类型无法直接判断是否相等则会报错 { if(a==b) return true; else return false;} //利用具体化实现特定数据类型的使用,具体化优先调用 template<>bool func(struct a,struct b) { if.....}