C++学习
一、基础语法:
1. 整型:
short: 2字节,1字节占8位,可表示的数据范围是-2^15~2^15-1, 第一位表示正负,所以数据范围只能是15次方 int: 4字节 long: 4字节 long long: 8字节
2. sizeof 统计数据类型(变量)所占内存的字节大小
3. 浮点型:
float: 4字节 float a = 3.14f double: 8字节
4. 字符型: char ch='a' //单引号 占一字节
5. 字符串
char str1[] = "hello world";
string str2 = "hello world";
6. 布尔: bool 占一个字节
7. 数据输入
int a = 0;
cout << "请输入a的值:" << endl;
cin >> a;
cout << "输入a的值是:" << a << endl;
8. goto 尽量不要用
9. 数组
/*定义数组*/
int arr1[1];
int arr2[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int arr3[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
/*二维数组*/
int arr1[2][3];
int arr2[2][3] = {{1, 2, 3}, {4, 5, 6}};
int arr3[2][3] = {1, 2, 3, 4, 5, 6};
constexpr int size = sizeof(arr2); /*数组占用的内存空间*/
constexpr int rowSize = sizeof(arr2[0]); /*第一行占用的内存空间*/
constexpr int length = size / rowSize; /*二维数组的行数(长度)*/
cout << length << endl;
10. 函数
int add(int *p1, int &num2, int num3) {
/*引用传值用&*/
num2 = 10; /*num2 的值已改变*/
*p1 = 20;
num3 = 35;
return 0;
}
int main() {
int a = 10;
int b = 20;
int c = 30;
add(&a, b, c);
cout << a << endl; /*变量值改变*/
cout << b << endl; /*变量值改变*/
cout << c << endl; /*变量值末改变*/
}
在C++的函数参数中传递对象时是值传递,建议使用引用传递&。(但是在php中函数参数中对象的传递方式默认为引用传递)
二、核心编程:
1. 内存四区:
代码区:
全局区:全局变量、静态变量、全局常量、 程序结束后由操作系统释放
栈区:函数里的数据在栈区,不要返回局部变量的地址
堆区:new 在堆区开辟数据,int *p = new int(10),程序员管理和释放,delete
2. 引用:
int a = 10;
int &b = a;
b = 20;
cout << a << endl; // 20
3. 函数占位参数
4. 函数重载
函数名相同,参数类型不同,顺序不同 或 数量不同
5. 类和对象
class Student1 {
public:
string name; /*姓名*/
int num; /*学号*/
void showDetail() const {
cout << "姓名:" + name + ",学号:" + to_string(num) << endl;
}
};
Student1 student1;
student1.name = "海龙";
student1.num = 10001;
student1.showDetail();
struct和class的区别:struct的默认权限是公有,class的默认权限是私有
class Person {
public:
string name;
/*构造函数*/
explicit Person(const string &name) {
this->name = name;
};
/*析构函数*/
~Person() {
cout << "Person Destructor" << endl;
};
};
C++没有对象clone方法,但是有拷贝默认构造函数,实例化时直接传入对象,可以生成新对象。
php对象作为参数的传递、赋值操作均是引用操作,因此需要使用clone方法复制对象。
初始化列表:
class Person1 {
public:
Person1(int a,int b): m_a(a), m_b(b) {
}
int m_a;
int m_b;
};
Person1 person1(10, 20);
cout << person1.m_a << endl;
静态成员变量:类内声明,类外初始化。
class Person2 {
public:
static int age;
};
int Person2::age = 12;
cout << Person2::age << endl;
静态成员函数:只可访问静态成员变量
对象的链式操作:方法返回要带*,return *this
class Person3 {
public:
explicit Person3(const int age) {
this->age = age;
}
/**
* 返回person3本身
* @param p
* @return
*/
Person3 &addAge(const Person3 &p) {
this->age += p.age;
return *this;
}
int age;
};
Person3 person3(10);
Person3 person3_1(20);
person3_1.addAge(person3).addAge(person3);
cout << person3_1.age << endl; //40
常函数:不可修改成员属性,但是用mutable修饰的成员属性可以修改。
class Person4 {
public:
explicit Person4(const int age, const int sex) {
this->age = age;
this->sex = sex;
}
void showAge() const {
// this->age = 15; const修饰的常函数,不可修改成员变量
this->sex = 1; /*mutable 修饰的成员变量可以在常函数中修改其值*/
cout << this->age << endl;
}
int age;
mutable int sex;
};
Person4 person4(18, 2);
person4.showAge();
常对象:const Person p; 不可修改成员属性,但是用mutable修饰的成员属性可以修改,常对象只能调用常函数。
友元:全局函数做友元,类做友元,成员函数做友元。
全局函数做友元:
class Building {
friend void showBuilding(Building &b);/*showBuilding 全局函数作为友元*/
public:
explicit Building() {
this->pubRoom = "客厅";
this->bedRoom = "卧室";
}
string pubRoom; /*客厅 公有*/
private:
string bedRoom; /*卧室 私有*/
};
/**
* 全局友元函数
* @param b
*/
void showBuilding(Building &b) {
cout << b.pubRoom << endl;
cout << b.bedRoom << endl; /*默认是不可以访问对象中的私有属性的,必须把该函数作为类的友元*/
}
int main() {
Building building;
showBuilding(building);
}
类做友元:
class Building {
friend class Friend;/*类做友元*/
public:
explicit Building() {
this->pubRoom = "客厅";
this->bedRoom = "卧室";
}
string pubRoom; /*客厅 公有*/
private:
string bedRoom; /*卧室 私有*/
};
/**
* 友元类
*/
class Friend {
public:
/**
* 构造函数注入build对象
*/
Friend() {
this->building = new Building();
}
Building *building;
/**
* 显示build的成员属性
*/
void showBuild() const {
cout << this->building->pubRoom << endl;
cout << this->building->bedRoom << endl;
}
};
int main() {
Friend friend01;
friend01.showBuild();
delete friend01.building;
}
成员函数做友元:
class Building;/*先声明build,便于在Friend时使用*/
class Friend {
public:
Building *building;/*引入Building作为成员属性注入,必须在前面先声明类 (循环引用)*/
Friend();
void showBuild() const;
};
class Building {
friend void Friend::showBuild() const;/*引入Friend作为友元 (循环引用)*/
public:
Building() {
this->pubRoom = "客厅";
this->bedRoom = "卧室";
}
string pubRoom; /*客厅 公有*/
private:
string bedRoom; /*卧室 私有*/
};
Friend::Friend() {
this->building = new Building;
}
void Friend::showBuild() const {
cout << this->building->pubRoom << endl;
cout << this->building->bedRoom << endl;
}
const Friend friend1;
friend1.showBuild();
delete &friend1;
运算符重载:operator+
继承:继承方式,1. public: 公众方式,2. protected: 把父类的public属性的改为protected,3. private: 私有继承,把父类的属性改为私有。
继承的方式是复制,会把父类中的成员复制到子类中,一定程度上会影响效率。
多态:虚函数:之类重写父类时要把父类函数定义为虚函数。
纯虚函数和抽象类:只要一个纯虚函数,这个类就是抽象类。虚析构,纯虚析构为了解决子类中堆区数据不能释放的问题
6. 文件操作
#include <fstream> /*包含头文件*/
/*写*/
ofstream fout;/*创建流对象*/
fout.open("D:/cpp/test.txt");/*打开文件*/
fout << "Hello World!\n";/*写数据*/
fout.close();/*关闭文件*/
/*第一种读*/
ifstream input("D:/cpp/test.txt");
string line;
while (getline(input, line)) {
cout << line << endl;
}
/*第二种读*/
ifstream ifstream;
ifstream.open("D:/cpp/test.txt", ios::in);
char buf[1024] = {0};
while (ifstream >> buf) {
cout << buf << endl;
}
/*第三种读*/
ifstream ifstream;
ifstream.open("D:/cpp/test.txt", ios::in);
char buf[1024] = {0};
while (ifstream.getline(buf, sizeof(buf))) {
cout << buf << endl;
}
/*第四种读*/
ifstream ifstream;
ifstream.open("D:/cpp/test.txt", ios::in);
string buf;
while (getline(ifstream, buf)) {
cout << buf << endl;
}
二进制写入文件
#include <fstream> /*包含头文件*/
class Person {
public:
char m_name[20];
int age;
};
ofstream fout;
fout.open("person.txt", ios::out | ios::binary); /*二进制 写的方式打开文件*/
if (!fout.is_open()) {
cout << "Can't open file";
return 1;
}
Person p = {"张三", 18};
fout.write(reinterpret_cast<const char *>(&p), sizeof(Person));
fout.close();
二进制读文件
#include <fstream> /*包含头文件*/
class Person {
public:
char m_name[20];
int age;
};
ifstream ifs;
ifs.open("person.txt", ios::in | ios::binary);/*以二进制只读方式打开*/
if (!ifs.is_open()) {
cout << "Error opening file" << endl;
return 0;
}
Person p{};
ifs.read(reinterpret_cast<char *>(&p), sizeof(Person));
cout << "Name: " << p.m_name << endl;
cout << "Age: " << p.age << endl;
ifs.close();
三、高级编辑
1. 模板:泛型编程、STL。
函数模板:如果函数模板和普通函数同时存在,优先调用普通函数;可以强制调用函数模板;函数模样也可以重载;如果有更好的配置,则优先调用函数模板(如普通函数的参数是int,传的参数是char,则优先调用函数模板);函数模板和普通函数尽量不要同时出现。
/**
* 声明一个模板
* @tparam T
* @return
*/
template<typename T>
void mySwap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
int a = 10;
int b = 20;
mySwap(a,b);/*自动推导数据类型:a 20 b 10*/
string s = "hello";
string s1 = "world";
mySwap<string>(s,s1);/*指定数据类型(建议):string world hello*/
类模板:
/*类模板*/
template<class NameType, class AgeType>
class PersonX {
public:
PersonX(NameType name, AgeType age) {
this->name = name;
this->age = age;
}
NameType name;
AgeType age;
};
int main() {
PersonX<string, int> p1("John", 10);
PersonX<int, string> p2(7758, "15");
cout << p1.name << "_" << p1.age << endl;
cout << p2.name << "_" << p2.age << endl;
}
类模板与函数模板的区别:类模板不能自动推导数据类型,类模板可以设置默认数据类型而函数模板不可以。
2. STL: Standard Template Library 标准模板库:
容器、算法、迭代器(容器和算法之能通过迭代器进行无缝连接):string、vector(读数组快)、deque(写数组快)、stack(栈容器)、queue、list、set、map等容器
vector:类似数组(头插数据要整体移动数据,适合做只读数据):empty()、resize(10)、size()数组中的个数、capacity()数组中的容量、push_back()、insert()、erase()、clear()、back()、front()等方法,shrink_to_fit():释放多余内存,reserve():预留空间
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v;
v.push_back(1);
v.push_back(2);
auto itBegin = v.begin();/*起始迭代器 1*/
const auto itEnd = v.end();/*结束迭代器 6619472*/
/*遍历1*/
while (itBegin != itEnd) {
cout << *itBegin << endl;
++itBegin;
}
/*遍历2*/
for (const int & it : v) {
cout << it << endl;
}
/*遍历3*/
ranges::for_each(v, [](const int &it) {
cout << it << endl;
});
return 0;
}
vector预留空间:v1.reserve(100000);
void test01() {
vector<int> v1;
const int *p = nullptr; /*v1 的首地址*/
int num = 0; /*动态开辟内存的次数*/
// v1.reserve(100000);
for (int i = 0; i < 100000; i++) {
v1.push_back(i);
if (p != &v1[0]) {
/*开辟一次内存*/
p = &v1[0];
num++;
}
}
cout << v1.size() << endl;/*100000*/
cout << v1.capacity() << endl;/*131072*/
cout << num << endl; /*18:存放100000个数字要开辟内存18次,解决办法是使用*/
}
int main() {
test01();
return 0;
}
deque容器:双端数组,适合做多端插入和删除。push_back、push_front、pop_back、pop_front、insert
list容器:双向循环链表,front、back、push_back、push_front、pop_front、pop_back、insert、resize、assign、empty、size、remove(删除指定值的元素)、sort、reverse、erase、clear。
list<int> l;
l.push_back(10);
l.push_back(20);
l.push_back(30);
l.push_back(40);
l.push_front(50);
l.sort([&](const int a, const int b) { return a > b; }); // 降序排序
set/multiset容器:集合,底层是二叉树,set不允许有重复元素。empty、insert、swap、clear、erase、find、count。
set<int> s1;
if (auto [fst, snd] = s1.insert(10); snd == true) {
cout<<"插入成功"<<endl;
}else {
cout<<"插入失败"<<endl;
}
if (auto [fst, snd] = s1.insert(10); snd == true) {
cout<<"插入成功"<<endl;
}else {
cout<<"插入失败"<<endl;
}
s1.insert(20);
//设置set排序为降序
set<int,greater<>> s;
s.insert(10);
s.insert(40);
s.insert(20);
s.insert(30);
/*40 30 20 10*/
for (const int it : s) {
cout << it << endl;
}
// 自定义数据类型 使用仿函数排序
class Human {
public:
explicit Human(string name, const int age, const int height) {
this->name = std::move(name);
this->age = age;
this->height = height;
}
bool operator<(const Human& rhs) const {
return this->age > rhs.age;
}
string name;
int age;
int height;
};
const Human h1("Tom", 12, 160);
const Human h2("David", 20, 172);
const Human h3("Steff", 20, 168);
const Human h4("Human", 15, 169);
const Human h5("HaiMei", 20, 188);
multiset<Human> set1;
set1.insert(h1);
set1.insert(h2);
set1.insert(h3);
set1.insert(h4);
set1.insert(h5);
for (const Human& it : set1) {
cout << it.age << endl;
}
pair对组:
pair<string, int> p("Tom", 24);
cout << p.first << p.second << endl; //Tom 24
map/multimap容器:高效率,高性能,key、value格式,会按key值默认排序。size、empty、swap、insert、clear、erase(key)、count(key)、find(key)
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(4, 40));
if (const auto it = m.find(3); it != m.end()) {
cout << "查找到数据了" << endl;
} else {
cout << "没查找到数据" << endl;
}
for (auto & it : m) {
cout << it.second << endl;
}
3. 函数对象(仿函数)
class myAdd {
public:
// 重载操作符 ()
int operator()(const int a, const int b) const {
return a + b;
}
};
constexpr myAdd add;
cout << add(1, 3) << endl; // 你调用函数一样调用类中的重载操作符
谓词:返回类型是bool类型的仿函数是谓词。一元谓词、二元谓词,(直接使用回调函数方便些)
vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
/*查找大于5的数字*/
auto it = find_if(v.begin(), v.end(), [](const int i) { return i >5; });
if (it == v.end()) {
cout << "没有找到" << endl;
} else {
cout << "找到" << endl;
}
内建函数对象:negate(取反)、plus(加法)、
#include <functional>
negate<int> n; /*取反*/
cout << n(50) << endl;/*-50*/
plus<int> plus; /*相加*/
cout << plus(10, 20) << endl; /*30*/
4. 常用算法:
for_each、transform、find、find_if、adjacent_fin、binary_search(二分查找,必须是有序的序列)、count、count_if、sort、random_shuffle(洗牌)、merge(两个序列必须是有序的)、reverse、copy、replace、replace_if、swap、accumulate(累加)、fill
(*注意返回值大部分是迭代器)
class Hum {
public:
Hum(string name, const int age) {
this->name = std::move(name);
this->age = age;
}
string name;
int age;
};
int main() {
vector<Hum> hums;
hums.emplace_back("John", 20);
hums.emplace_back("Marvine", 30);
hums.emplace_back("David", 40);
hums.emplace_back("Staff", 50);
// 条件查找
if (const auto it = find_if(hums.begin(), hums.end(), [](const Hum &hum) { return hum.age > 30; });
it != hums.end()) {
cout << "找到大于30岁的人了," << it->name << endl;/*David*/
}
}
vector<Hum> hums;
hums.emplace_back("John", 30);
hums.emplace_back("Jane", 20);
hums.emplace_back("Dvid", 40);
for (auto &hum: hums) {
cout << hum.name << " " << hum.age << endl;
}
cout << "-----------"<< endl;
// 大于30岁的替换成新的
ranges::replace_if(hums, [](const Hum &h) {return h.age>20;},Hum("xxx", 100));
for (auto &hum: hums) {
cout << hum.name << " " << hum.age << endl;
}
常用集合算法:set_intersection(求两个容器的交集)、set_union(并集)、difference(差集)
标签:const,cout,int,age,back,笔记,学习,C++,函数 From: https://www.cnblogs.com/longfeiPHP/p/18618942