注:本文章所写内容是小编复习所看的。记录的是一些之前模糊不清的知识点。详细c++内容请移步至小编主页寻找。
竞赛小技巧
竞赛中cin/cout用不了(没有办法刷新缓冲区,导致cin/cout与缓冲区绑定)
解决办法:(加以下三行代码)
//或则 换scanf/printf
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
类和对象上
namespace命名空间域
不同的域可以定义相同的变量
c++中的域:函数局部域,全局域,命名空间域,类域
::域作用限定符:默认查找全局变量
cout/endl/cin定义在<iostream> iostream 在命名空间域std中
缺省参数
全缺省:每个变量都缺省
半缺省:一部分变量缺省,一部分不缺省(缺省顺序从右向左连续缺省,不能间隔不能跳跃,
传参时从左到右)
缺省函数定义和声明分离时是不能同时出现的(规定)
eg:
stack.h
void Sinit(St*st,int n=100);//生明给
stack.cpp
void Sinit(St*st,int n=200);//不允许
stack.cpp
void Sinit(St*st,int n);//允许
函数重载
要求:同一命名域名(不同命名域名空间域可以有相同函数)
同名函数(不同参数类型或则不同参数个数或不同参数顺序<int,char>//<char,int>)
注:返回值不同不是函数重载
引用
引用的特性
1.引用必须初始化
int& ra;//不清楚是取得谁的别名
2.一个变量可以有多个引用(可以引用引用对象)
3.引用一旦引用一个实体,再不能引用其他实体
引用的使用
注意:做返回值
eg:修改栈顶元素
int SStop(ST& rs){//获取栈顶元素
return rs.a[rs.top-1];
}
SStop=3;//修改不允许 因为返回值返回时会生成一个临时变量(具有常性)不能修改//如果使用引用作返回值(不会产生临时变量直接把数组top位置返回),则可以避免类似情况发生
int& SStop(ST& rs);
const引用
引用const对象必须要用const引用
//错误示范(权限被放大)
/*const int a = 20;
int& ra = a;*/const int a = 10;
const int& ra = a;//正常权限int b = 30;
const int& rb = b;//权限缩小const int& ra=30//常量用const引用const int& rb=(a+b);//(a+b)为临时变狼具有常性 正常权限用const 引用//注:一些计算表达式结过,或则变量类型转换都会产生一个临时变量(临时变量具有常性)
引用和指针的区别
1.引用是给变量取别名(本身不开空间),指针式取变量的地址(指针本身就要开空间)
2.引用必须初始化,指针可以不初始化 。
3.引用只能引用一个对象,指针可以指向多个对象
4.引用直接访问变量,指针需要解引用
5.sizeof(引用变量),sizeof(指针,指针变量 32-4 64-8)
6.引用没有空指针形式,引用可能出现野指针
内联函数(inlline)
适用于频繁调用短小函数
作用:替代宏(#define add(a,b) ((a)+(b))
对于宏替换的目的就是不在建立函数(减少函数栈帧),从而使空间不在浪费。
对于inline函数就是在函数前面添加关键字inline(debug版本下不在在乎性能便于调试默认不展开)
inline int add(){
}
debug版本下调试的方法:(更改项目属性c/c++ 常规为程序数据库,优化改 内敛只适用于inline)
注1:inline函数只是一个建议,对于编译器来讲合理的地方加inline可以展开,不合理的地方加inline编译器也不会展开。
注2:inline函数不建议做声明和变量分离(inline无地址)
nullptr
c语言中NULL的存在是宏替换的存在,define NULL 0
在c++中函数重载时如何传NULL则会出现歧义。
nullptr可以转化成任意类型的指针但不能转化成整形。
类和对象(上)
class{_成员变量成员函数}
class未加访问限定符默认为private,struct默认为public
对于公有和私有简单理解(实例化对象时是否能访问到对应的函数)
对于类成员函数声明和定义分离要指定类域
类域
不同类域可以定义相同名称.
类的实例化
对于类里边的成员变量只是声明(声明是该变量时什么类型,并未开空间)。
对象大小计算
对于类对象大小计算方法:只计算成员变量的大小(每个对象有各自得的成员变量),不计成员函数的大小(成员函数默认放在一个地方,对象调用时调用同一个成员函数)
如果类中没有成员变量那么类对象的大小为1
为什么要内存对齐
cpu读取数据时并不是从任意地方开始读取的,cpu一次性读取指定整数倍位置(如果不对齐则可能数据读取不对)
this指针
this指针实际是做为一个参数(所以this指针存放在栈中)
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A {
public:void Print() {cout << this << endl;cout << "A.Print()" << endl;}int _a;
};
int main() {A* p = nullptr;p->Print();//p->正常来讲是解引用,但是Print函数并不是在p类中所以该地方并不是解引用,所以不会报错,Print(&p)传nulptr并不是报错p->_a=1;//_a是成员变量需要对指针进行解引用,又因为p是空指针,所以会报错。 return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A {
public:void Print() {cout << this << endl;cout << "A.Print()" << endl;cout<<_a<<endl//通过this指针访问——athis->a但是this指针为空所以会报错。}private:int _a;
};
int main() {A* p = nullptr;p->Print();//p->正常来讲是解引用,但是Print函数并不是在p类中所以该地方并不是解引用,所以不会报错,Print(&p)传nulptr并不是报错p->_a=1;//_a是成员变量需要对指针进行解引用,又因为p是空指针,所以会报错。 return 0;
}
类和对象中
默认成员函数
构造函数
1.函数名与类名相同,不需要返回值(void也不用),功能:初始化对象)
2.对象实例化时系统会自动调用相应的构造函数。
3.构造函数(有参数构造和无参数构造 构成构造函数函数重载)。
注意:全缺省和无参不能同时存在
4.什么叫默认构造函数?
无参的,全缺省的,我们不写系统默认生成的构造函数成为默认构造函数(在一个类中三者仅且仅能出现一个)。
c++类型分配
a.内置类型(基本类型)int/double
b.用户自定义类型 class/struct 修饰的类型
不写,编译器自动生成的的对内置类型的初始化不确定,对自定义类型如果没有对应的默认构造不进行初始化则会报错。
析构函数(函数销毁)
功能:完成类对像中的资源清理释放
无参数(不能重载),无返回值,与构造函数相反,前边加~
析构顺序:后定义的先析构
拷贝构造函数
规定:拷贝构造函数的第一个参数是对自身类类型的引用,其他任何额外的参数都有默认值,符合以上条件的函数叫拷贝构造函数。
拷贝构造函数的特点:
1.拷贝构造函数是构造函数的一个重载。
2.拷贝构造函数的第一个参数是对自身类类型的引用,如果采用传值传参这则会引发无穷递归。
c++规定:
函数的传值传参需要先调用拷贝构造函数。
贝构造对内置类型完成值拷贝/浅拷贝(一个字节一个字节拷贝),对于自定义类型会调用他的拷贝构造函数。
注意:像日期类这样没有开任何资源空间的类是可以不用自己写拷贝构造函数,但是像栈/队列有开辟新空间的类如果要像完成拷贝必须自己写·。
如下:如果我们不自己写,编译器默认生成的拷贝构造函数,会对栈完成值拷贝/浅拷贝,这样的话拷贝后两块资源同时指向同一个位置,那么析构函数的时候就会释放该空间两次,程序就会崩溃。
解决方法:
重新开一个相同大小的空间,memcpy进行拷贝即可
传值返回与传引用返回
传值返回会产生一个临时对象的拷贝,传引用返回不用产生临时拷贝,但是传引用返回(返回值是全局或则出来出了函数还能找到,如果返回的是函数局部域中的变量,那么 传引用返回时函数栈帧已经销毁,返回的引用就成为野引用)。
赋值重载函数
运算符重载
载,若没有运算符重载则编译会报错。
2.参数个数与运算对象时一一对应的
3.格式:operator + (运算符 )
4.调用方式:a.显示调用 operator+=(Date d1,Date d2);//x1==x2
建议:重载函数放在类里边,第一个参数传给this指针
调用方法:x1.operator==(x2) //x1==x2 x1给this,x2=传一个参数
5.不能重载的运算符:.* :: . sizeof ?:
6.重载运算符至少有一个类类型的参数operator+(int x,int y)//毫无意义 operator+ (Date& d1,int x)//ok
赋值运算符重载
赋值运算符重载是指对已经存在的两个对象进行拷贝赋值
拷贝构造是指一个已经初始化的对象去拷贝另一个没有存在的对象
一元运算符重载
d1++,++d1区分
后置++增加一个int形参
d1++:operator++(int);
++d1: operator();
取地址运算符的重载
const成员函数
const去修饰成员函数把const放在成员函数后边。
简单理解:
实例化对象时如果对象为 const Date d3(2004,4,11);
对象被const修饰,假如去调用类中Print函数,传参第一个为Date* this,(由const Date* d3->Date* this 显然求安县被放大)为了防止权限被放大我们要在该函数后边+const void Print() const{}
取地址运算符的重载
Date* operator&(){
return this; //this就是实例化对象地址
return nullptr; //可以保护自己程序地址
}
const Date* operator&()const {
return this;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date {
public:Date* operator&() {//return nullptr;return (Date*)0x211;}const Date* operator&() const{return nullptr;}
};
int main() {Date d1;cout <<&d1<< endl;return 0;
}
类和对象下
1.再探构造函数
初始化列表(初始化变量的地方)
引:在初始化列表不管显示写成员变量还是不写 成员变量都会走初始化列表。
1.简单理解:类似于构造函数对变量进行初始化,但是,初始化列表对变量进行初始化时并不是在函数体内进行的,而是在构造函数外边进行初始化,初始化格式以:(冒号)开始,,(逗号)分割的形式,而且每个初始化变量的后边都要加一个括号。
eg:
Date (int year,int mouth,int day)
:_year(year)
,_mouth(mouth)
,_day(day)
{}
2.c++规定:a. 初始化列表是类中每个成员变量定义的地方
3.只能在初始化列表进行初始化不能再函数体内进行初始化的类型
a.由const修饰的成员变量只能在初始化列表进行初始化
b.引用类型的成员变量必须在初始化列表进行初始化
c.对于自定义类型如果该自定义变量有对应的默认构造(原本类里边),那么可以不在初始化列表对它进行初始化,如果没有该变量的默认构造,则需要在初始化列表进行初始化,若存在默认构造且在初始化列表对该变量也有进行初始化,则优先使用初始化列表的初始化。
3.初始化列表的缺省值:
初始化列表的初始值是在,成员变量定义的地方进行赋值(虽然该法地方进行赋值,但是地方仍然是变量声明的地方并没有开空间)
总结:
2.类型转换
对于类型转换,一个类型转换成另一个类型,其实就是把该类型转换成一个临时变量,再把临时变量复制给转换类型。
如果不想类型转换在构造函数前面加关键字explicit
3.static静态成员
特性:
1.静态成员变量必须在类外面进行初始化。
2.静态成员变量不属于类对象(存放在静态区),不存在类对象中,但被所有类所共享。
3.静态成员函数:我们无法正常访问静态成员变量,因为他是私有保护,要i选哪个访问静态成员变量只有用静态成员函数。
静态成员函数没有this指针,只能访问静态成员变量,不能访问其他成员变量。非静态访问静态随便访问。
static int GetCount(){
return count;
}
//调用方法
cout<<A::GetCount<<endl;
4.友元函数
作用:突破类域的访问限定符
1.要想访问私有成员变量则只需在该函数头部加friend 放在类中(只是一种声明,并不是成员函数)
2.友元类:: friend class B 为了访问私有成员变量。
3.友元类特性:单向的,不能交换,不能传递
注意:友元破坏了c++封装特性,不建议多用。
5.内部类
定义:一个类定义在另一个类的里边
1.内部类跟定义的全局类类似,只不过受类类域的限制,并不包含于外部类(计算大小时并不计算内部类)。
2.默认内部类是是外部类的友元(可以直接访问外部类的成员变量)。
6.匿名对象
方便理解:匿名对象就为了我们方便。
注:1.生命周期只在当前这一行。
A aa;//有名对象
A();
A(1);//匿名对象