文章目录
c++学习笔记
by jokersio
关于语法:
字符串相关
- getline(cin,s) 可以string和char
- cin.getline() 只能char
string部分函数
string s
s1=s.substr(st,len) //从st位置开始截取一段长度为len的字串
s.c_str() //将string转换为char *类型
strcmp(s1,s2) //比较字符串大小,s1==s2 返回0,s1<s1 返回负数, s1>s2 返回正数
for_each:(用auto)
-
for(type v:array)修改不反应
-
for(type &v:array)修改反应到array里
printf 格式控制
printf("%-8d",i); //左对齐共占8个字符
printf("%+5d",i); //右对齐共占5个字符
printf("%04d",x);//保持四位数不满用前导0补
cout浮点数格式控制
#include<iostream>
#include<iomanip> //输出流控制,setiosflags(ios::fixed),setprecision(n)的头文件
using namespace std;
int main()
{
double n = 50.26548;
printf("%.4f", n);
cout << endl; //打印输出小数点后4位,会四舍五入
cout << setprecision(4) << n << endl;//输出4位有效数字,包括整数和小数部分,会四舍五入
cout << setiosflags(ios::fixed) << setprecision(4) << n << endl;
//输出小数点后4位,会四舍五入,会影响后面的setprecision()输出
cout << setprecision(4) << n << endl;
//受前面影响,只输出小数点后4位,而不再是包括整数部分的7位,会四舍五入
cout << setiosflags(ios::fixed) << setprecision(4)<<floor(n * 10000)/10000<< endl;//不会四舍五入,保留几位小数就乘和除10的几次方
system("pause");
return 0;
}
switch 语法
switch(x) //x只能为int
{
case 1:
{
x++;
break;
}
case 2:
{
x--;
break;
}
default: cout<<"ha";
}
文件输入输出
//需要头文件fstream
ifstream fin("a.txt");
string a;
fin >> a;//从文件输入
ofstream fout("a.txt");
fout << "hello"; //输出到文件里
cout << "hello"; //输出到控制台
//需要头文件stdio.h
freopen("a.txt","w",stdout);
freopen("a.txt","r",stdin);
判断类型
typeid(a)==typeid(float)
指针与引用
引用调用
替代指针的技术(LJ推荐)
如果要传数组就用array和vector
改变参数的值
bool div(double a,double b,double& c)
{
if(!b)
return 0;
c=a/b;
return true;
}
//调用
bool flag=div(a,b,c);
//就不用加指针了
//会改变主函数变量中c的值
传递大参数
void donothing(vector<int> &b)
{
}
int main()
{
vector<int> a(1000000);
donothing(a);
}
全部使用引用
//全部加引用没有损失,如果是只读参数加const
bool div(const double a,const double b,double& c)
{
if(!b)
return 0;
c=a/b;
return true;
}
const指针
找距离const最近的变量类型const int* p
*p不能改 p可以改int* const p
*p可以改 p不能改
左值引用与右值引用
左值就是正常的引用,右值是引用常量
int &&r=10
面向对象
结构和类辨析
- 结构:默认是public,有构造函数(默认)
- 类:默认是private,无构造函数(需声明)
类的一些注意事项
-
类加上了const之后
任何修改成员变量的函数无法调用
如果要调只读函数需要加const
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9P6ISfNc-1627004043427)(C:\Users\kevin\Desktop\c++学习笔记\const类只读.png)]
-
this指针(类比python中的self)
-
enum{maxn=10} //用枚举定义常量
-
静态成员函数不允许访问成员变量(只能访问静态变量)
-
构造函数用初始化列表的情况():如果会被继承,或者会被引用调用
rent(int w,int h):width(w),height(h)
{
}
友联函数(c++特有不推荐)
class car{
public:
int b;
friend int totalweight(boat n,car m);//友元函数的定义,friend+返回值类型+函数名+(参数)
}
只要在类里声明,但不是类的成员函数
在主函数里正常调用
之后在外部写定义时可以调用private
// 正常应该写一个函数返回private变量的值
重载运算符
类内部写法
class student{
private:
string name;
int score;
//在内部写默认第一个变量为this指针
public:
int operator +(const node &a)
{
return this->score+a.score;
}
}
输入输出输出运算符重载
ostream&operator<<(ostream& os,const Complex &c)
{
os<<c.u<<"+"<<c.v<<"i";
return os;
}
istream&operator<<(isstream& is,Complex &c)
{
is>>c.u>>c.v;
return is;
}
//注意os时后面要加const,istream不加const
//在类里调用时,一般要写成友联
重载++
MyTime MyTime::operator ++()
{
second++;
if(second==60){minute++;second=0;}
if(minute==60){hour++;minute=0;}
hour%=24;
return *this;
}
构造函数中使用new和delete的注意事项
- 如果在构造函数中使用new初始化指针成员,则应在析构函数中使用delete
- new和delete对应,new[]和delete[]对应
- 如果有多个构造函数,应使用相同的方式使用new,因为析构函数只有一个
拷贝构造函数
class Complex{
public:
double real, imag;
Complex(double r,double i){
real = r; imag = i;
}
Complex(const Complex & c){
real = c.real; imag = c.imag;
cout<<"Copy Constructor called"<<endl ;
}
};
调用情况:
- 当用一个对象去初始化同类的另一个对象
Complex c2(c1);
Complex c2 = c1;
//两条语句等价
- 如果函数的返冋值是类 A 的对象,则函数返冋时,类 A 的复制构造函数被调用。
A Func() {
A a(4);
return a;
}
- 如果函数 F 的参数是类 A 的对象,那么当 F 被调用时,类 A 的复制构造函数将被调用。
void Func(A a){ }
深拷贝与浅拷贝
int main()
{
int *a=new int[10];
int *b=a;//浅拷贝
//深拷贝
int *c=new int[10];
for(int i=0;i<10;i++)
c[i]=a[i];
}
类继承
并不推荐使用。相较于继承,更推荐使用组合。
c++的继承机制较java与python更为复杂,也更容易出现bug,比如一个类可以继承两个父类。
可以类比python的继承方式。
- 继承构造函数
class sqare:public rent{
public:
square(int w):rent(w,w){
}
}
- public继承可以继承public 和protected
- protected和private继承(有表)(最好不要用)
虚基类
由于C++支持多重继承,所以对于一个派生类中有几个直接父类,而几个直接父类中有几个可能分别继承自某一个基类(就是父类的父类),这样在构造最终派生类时,会出现最终派生类中含有多个同一个基类的情况,就会产生二义性的问题(不知道该调用哪个基类的成员变量和函数),为解决此问题,需要使用虚基类,即只对此基类生成一块内存区域,这样最终派生类中就只会含有一个基类了 。
class A {
public:
void printA() {cout<<"this is A\n";}
};
class B:virtual public A;
class C:virtual public A;
class D:public B,public C;
常量
常量对象调用函数时,只能调用常量函数
void Test(const CAR &x)
{
x.Show();
}
将show函数申明为常量
void Show() const
关于STL
结构体lower_bound(内部重载运算符)
#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
int val,id;
bool operator < (const node &b)
{
if(val!=b.val)
return val<b.val;
else
return id<b.id;
}
}a[100000+50];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i].val),a[i].id=i;
sort(a+1,a+n+1);
cout<<lower_bound(a+1,a+n+1,(node){-100,0})-a<<endl;
cout<<lower_bound(a+1,a+n+1,(node){-2,0})-a<<endl;
cout<<lower_bound(a+1,a+n+1,(node){1,0})-a<<endl;
cout<<lower_bound(a+1,a+n+1,(node){100,0})-a<<endl;
}
关于set
是天梯赛L1-005的题解,set模板应用
#include<bits/stdc++.h>
#define MAXN 110
#define for1n(i, n) for (int i = 1; i <= n;i++)
using namespace std;
int m,n,num[MAXN];
set<int> u[MAXN];
void query(int x,int y)
{
int same=0;
for(auto id:u[x])
{
if(u[y].find(id)!=u[y].end())
same++;
}
int sum=u[x].size()+u[y].size();
int nt=sum-same;
printf("%.2lf%%\n",same*1.0/nt*100);
}
int main()
{
cin>>n;
for1n(i,n)
{
cin>>num[i];
for1n(j,num[i])
{
int x;
cin >> x;
u[i].insert(x);
}
}
cin>>m;
for1n(i,m)
{
int x,y;
cin >> x >> y;
query(x, y);
}
cin.get();
}
杂类知识
多文件编程
- .h文件放函数声明
- .cpp文件放函数的定义
- .hpp声明实现都有,可以减少cpp文件的数量
- 编译时将所有的cpp文件一起编译
内联函数
-
在声明和定义前加inline
-
不能递归,编译出来的exe较大
-
一般是简单函数
-
提高调用速度,节省空间
-
实现在头文件里
异常检测
传统处理:(推荐)
- abort()或exitshiyo()退出程序
- 函数返回“错误码”
异常机制:
- 引发异常
- 捕获异常
- 使用try