C++学习笔记
- string的length和size都是O(n)
- nth_element(arr.begin(),arr.begin()+3,arr.end());
O(n)比sort排序快 - 1s时限内能做的运算次数大约为1e8,根据复杂度来算是否会超时
- G++在输出double时不能用%lf,要用%f
- 注意多组拥立时的EOF、初始化,初始化的常数时间也得估计好
- int表示范围-32769~32767
- 单精度float,占用4个字节,有效数字范围为7位有效数字,赋值时末尾加个f
- 双精度double,占用8个字节,有效数字范围为15~16个有效数字
- 默认情况下,输出一个小数会显示6位有效数字
- a对应的ASICII码为65,A对应的ASCII码为97
- 转义字符:
- 反斜杠 \
- 水平制表符 \t
- swith语句判断时候只能是整形或字符型,不可以是一个区间
- 一维数组名的用途:
- 可以统计整个数组在内存的长度
- 可以获取数组在内存中的首地址
- C++ 0x代表十六进制
- 二维数组定义事一定要定义列数
- 二维数组名的用途:
- 可以统计整个数组在内存的长度
- 可以获取数组在内存中的首地址
- 自己定义的函数写在main函数前面
- 值传递时,形参发生任何的改变都不会影响实参
- 函数声明后面有分号,函数定义后面没有
- 32位操作系统中指针占4个字节,64位操作系统中指针占8个字节
- 空指针用于给指针变量进行初始化,不可以进行访问,0~255之间的内存编号是系统占用的,因此不可以访问
- const int*常量指针,指向常量的指针(可以理解为常量的指针),指针的指向可以修改,但是指针指向的值不可以修改
- int* const p 指针常量,指针类型的变量(可以理解为指针的常量),指针的指向不可以修改,指针指向的值可以修改
- const int* const p 指针指向的值和指针的指向都不可以修改
- 初始结构体的方式:
- struct Student s1;
- struct Student s2 =
- 在定义结构体时顺便创建结构体变量
- 结构体定义时struct关键字不能省略,使用时可以省略
- 数组作为函数参数,只能是指针传递
- case语句中不可以定义变量,加了{}后相当于在语句块中定义变量就可以
case 3:
{
cout << "请输入删除联系人的姓名:" << endl;
string name;
cin >> name;
if(isExist(&abs,name) == -1){
cout << "查无此人" << endl;
}else{
cout << "找到此人" << endl;
}
}
break;
- C++程序在运行时,将内存划分为4个区域:
- 代码区:存放函数题的二进制代码,由操作系统进行管理的
- 全局区:存放全局变量和静态变量以及常量
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
- 变量本质就是内存,申请完内存就是结构体变量了
- 引用:给变量起别名,数据类型 &别名 = 原名
- 引用必须初始化
- 引用初始化后不可以修改
- 引用传递,形参会修饰实参
- 引用做函数的返回值:
- 不要返回局部变量的引用
- 函数的调用可以作为左值
- 静态变量存放在全局去,全局区上的数据在程序结束后系统释放。
- 局部变量存放在栈区
- 引用本质是指针常量
- 1.需要首先明确的是,形参改变实参这种情况只可能发生在地址传递或引用传递之中。2.“ 防止形参改变实参”的意思是:在函数中可能会对形参的值进行修改,但是我们有时又不想让实参跟着改变,那么就可以用const来修饰形参。
- 如果某个位置已经又了默认参数,那么从这个位置往后,从左到右都必须有默认值
- 如果函数声明有默认参数,函数实现就不能有默认参数,声明和实现只能有一个有默认参数
- 占位参数也可以有默认参数
- 函数重载(函数名相同,提高复用性)满足条件:
- 同一作用域下
- 函数名称相同
- 函数参数类型不同,或者个数不同,或者顺序不同
注意:函数的返回值不可以作为函数重载的条件
- 函数重载不要默认参数,避免二义性出现
- c++面向对象的三大特性:封装、继承、多态
- 通过类来创建一个对象的过程就叫实例化
- 类的成员一般加m_前缀(member),可以清晰的表示他是一个类的成员
- 类中的属性和行为统称为成员
- 属性:成员属性,成员变量
- 行为:成员函数,成员方法
- 三种访问权限:
- 公共权限 public 成员类内可以访问 类外也可以访问
- 保护权限 protected 成员类内可以访问 类外不可以访问 子类可以访问父类的保护内容
- 私有权限 private 成员类内可以访问 类外不可以访问 子类不可以访问父类的保护内容
- struct和class默认的访问权限不同:
- struct默认权限为公共
- class默认权限为私有
- 成员属性设置为私有:
- 可以自己控制读写权限
- 对于写权限,我们可以检测数据的有效性
- 静态成员变量:
- 所有对象共享一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
- 静态成员变量不属于有某个对象上,所有成员共享同一份数据,静态成员变量也是有访问权限的,类外访问不到私有的静态成员变量。
- 静态成员变量有两种访问方式:
- 通过对象进行访问
- 通过类名进行访问
- 静态成员函数(也有访问权限):
- 所有对象共享一个函数
- 静态成员函数只能访问静态成员变量,不可访问不静态成员变量,无法区分是那个对象的非静态成员变量
- 只有非静态成员变量才属于类的对象上,静态成员变量、非静态成员函数和静态成员函数都不属于类的对象上
- 空对象占用内存空间为1,c++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置,每个空对象也应该有一个独一无二的内存地址
- this指针指向被调用的成员函数所属的对象,this指针是隐含每一个非静态成员函数内的一种指针,this指针不需要定义,直接使用就可以。
- this指针的用途:
- 当形参和实参相同时,可以用this指针来区分,(解决名称冲突)
- 在类的非静态成员函数中返回对象本身,可以用return *this
- 如果要返回本体,要用引用的方式进行返回:
class Person{
public:
Person(int age){
this->age = age;
}
Person& PersonAddAge(Person& p){
this->age += p.age;
return *this;
}
int age;
};
if(this == NULL) {
return;
}
- 常函数:
- 成员函数后加const后我们称这个函数为常函数
- 常函数内不可以修改成员属性
- 成员属性声明时加关键字mutable,在常函数中可以修改
常对象: - 声明对象前加const称该对象为常对象
- 常对象只能调用常函数
- this指针的本质是指针常量,指针的指向不可以修改
void showPerson()const{
// this->m_A = 100;
}
this相当于 const Person* const this(常指针常量),在成员函数后面加const,修饰的是this指向,让指针指向的值也不可以修改.
63. 属性前加mutable,在常函数中可以修改此属性的值
64. 在对象前加const变成常对象,不可以修改对象的属性,常对象只能调用常函数,不可以调用成员函数,因为成员函数可以修改属性
65. 全局函数函数申明加到要访问的类中,前面加上friend访问权限,这样全局函数就可以访问到该类中的private属性和方法
66.
//类外写构造函数
Building::Building(){
m_SettingRoom = "客厅";
m_BedRoom = "卧室";
}
//类外写成员函数
void GoodGay::visit(){
cout << "好基友类正在访问:" << building->m_SettingRoom << endl;
}
在函数名称前加上作用域
- 在要访问的类中加上class声明语句,并且前面加上friend关键字,这个类的private属性和方法就可以被friend类访问
class GoodGay{
public:
GoodGay();
void visit();//让visit函数可以访问Building中私有成员
void visit2();//让visit函数不可以访问Building中私有成员
Building * building;
};
class Building{
friend void GoodGay::visit();
public:
Building();
public:
string m_SettingRoom;
private:
string m_BedRoom;
};
ostream& operator<<(ostream& out, Person& p){
cout << "m_A = " << p.m_A << " " << "m_B = " << p.m_B;
return cout;
}
重载左移运算符配合友元可以实现输出自定义数据类型
70. 赋值运算符就是从左往右运算的
71. 函数调用运算符()重载,由于使用起啦非常类似于函数调用,因此称为仿函数,仿函数非常灵活,没有固定的写法
72. 默认的访问属性为private,保证了数据的安全性 而c语言的结构体中的默认访问属性为pubic
73. 子类和父类同名属性和函数要加上作用域
cout << s.Base::m_A << endl;
s.Base::func();
-
如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏父类中所有同名成员函数,如果想访问到父类中被隐藏的同名函数,要加作用域
-
cout << "Base下m_A = " << Son::Base::m_A << endl;第一个::代表通过类名的方式访问,第二个::代表访问父类作用域
-
find查找是从左往右,rfind查找是从右往左,find找到字符串后但会查找的第一个字符位置,找不到返回1,replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串
-
at会进行越界检查[]不会
-
include
通过max_element(n,n + m)可以获得数组n中前m个数最大的那个数的指针,通过*max_element(n,n + m)即可获得这个数,min_element同理
-
s1.compare(s2),若两个字符串相等,则返回0
-
运算符 delete 具有类型 void 的结果,因此不返回值。运算符 delete 具有类型 void 的结果,因此不返回值。这些 new 运算符 delete 还可用于内置类型,包括数组。 如果 pointer 引用数组,请将空括号放在前面 ([]) pointerint* set = new int[100];
//use set[]
delete [] set; -
const指针就像一般的const变量赋值给任何类型相同或可以转换的变量,而指向const对象的指针可以用const对象或非const对象初始化,指向非const对象的指针只能用非const对象初始化。最后的int *p=q由于int *p为非const对象指针故不能用const对象初始化。
-
不带头结点的单链表head为空的判定条件是head=NULL。
-
可以用带表头附加结点的链表表示线性表,也可以用不带头结点的链表表示线性表,前者最主要的好处是使空表和非空表的处理统一
-
构造函数和析构函数不能继承
-
调用基类构造函数的顺序是按照声明派生类时基类出现的顺序
-
为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类,否则仍然会出现对基类的多次继承
-
多重继承时,不仅要对直接继承的基类进行初始化,还要对虚基类进行初始化
-
-
派生类对象可以向基类对象赋值
-
派生类对象可以替代基类对象向基类对象的引用赋值
-
如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类对象
-
派生类对象的地址可以赋值给指向基类对象的指针变量(注意此时指向的是派生类从基类中继承的部分)
-
通过指向基类对象的指针,只能访问派生类中的基类成员,而不能访问派生类中增加的成员
-
-
使用静态成员变量的时候,在类外要进行初始化,int Stud::num = 0;不必在写static
-
抽象类的唯一用途是为派生类提供基类,纯虚函数的作用是作为派生类中的成员函数的基础,并实现动态多态性。
-
抽象类不能被实例化,因为大多数时候的抽象类的纯虚函数都没有相应的实现。
由于基类的指针(引用)可以使用子类的函数,这样,我们通过抽象类的指针可以去调用派生类对象的函数。
- 数据封装就是数据抽象,即信息隐藏,而继承是实现程序复用的基础。
- 位运算中的与运算,奇数的二进制最后一位一定是1,和1与运算得1,和0与得0
- string类型通过下标运算符重载可以用下标访问
- s.find('h')返回的为字符的下标,s.rfind('h')为从右往左找
- 要读取一行输入,必须使用 cin.getline 而不是 getline 函数,getline 函数使用两个用逗号分隔的参数。第一个参数是要存储字符串的数组的名称。第二个参数是数组的大小。当 cin.getline 语句执行时,cin 读取的字符数将比该数字少一个,为 null 终止符留出空间。
#include <iostream>、
using namespace std;
int main()
{
const int SIZE = 81;
char sentence[SIZE];
cout << "Enter a sentence: ";
cin.getline (sentence, SIZE);
cout << "You entered " << sentence << endl;
return 0;
}
-
注意:>> 是会过滤掉不可见字符(如 空格 回车,TAB 等)
-
cin.getline() // 接受一个字符串,能够接收空格并输出,getline() // 接受一个字符串,能够接收空格并输出,需包含“#include
”,和cin.getline()相似,可是cin.getline()属于istream流,而getline()属于string流,是不同的两个函数 -
include
using namespace std;
int main()
{
const char* name[] = {"basic","fortran","c++"};
const char ** p;
p = name + 2;
cout << name[2] << endl;
cout << *p << endl;
cout << **p << endl;
return 0;
}
name是二维数组首元素的地址,即"basic"的地址,*p为name[]数组中第三个元素的地址,即"c++"的地址,**p为* *(name + 2),即"c++"的首元素"c"
100. 用struct声明的类默认为public,class声明的类默认为private
101. 成员函数不占用实例的空间
102. 常成员函数(常函数)
在一个成员函数参数表后面加const修饰,表示这个函数是常成员函数。
返回类型 函数名(形参表) const{函数体}
常函数中的this指针是一个常指针,不能再常函数中修改成员变量的值。(注:被mutable关键字修饰的成员变量,可以在常函数中被修改)
非常对象既可以调用常函数也可以调用非常函数,但是常对象只能调用常函数,不能调用非常函数。(注:常对象也包括常指针或常引用)
函数名和形参相同的成员函数,其常版本和非常版本可以构成重载关系,常对象调用常数版本,非常对象调用非常版本。
103. class后面没有()
104. class的静态成员变量要初始化
如
```c++
static int count ;
static int showCount()
{
cout << count << endl;;
return count;
}
int Point::count = 0;
- (*指针变量名)”两端的括号不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针而是一个函数声明了,即声明了一个返回值类型为指针型的函数。
- public,可以被任何类访问。
protected,可以被同一包中的所有类访问,可以被所有子类访问,不管子类是否在同一包中,即子类不在同一个包中也可以访问。
private,只能被当前类所访问。
缺省,可以被同一个包中的所有类访问。类的缺省访问即默认访问,故其权限为私有的 - this只能在成员函数中使用。全局函数、静态函数都不能使用this。实际上,成员函数默认第一个参数为T * const this。类内定义的静态方法不能指向实例本身,也就是没有this指针。
- this在成员函数的开始执行前构造,在成员的执行结束后清除。
include
using namespace std;
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 ;
}
};
int main(){
Complex cl(1, 2);
Complex c2 (cl); //调用复制构造函数
cout<<c2.real<<","<<c2.imag;
return 0;
}
120. 复制构造函数在以下三种情况下会被调用。
- 当用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用。例如,下面的两条语句都会引发复制构造函数的调用,用以初始化 c2。
- 如果函数 F 的参数是类 A 的对象,那么当 F 被调用时,类 A 的复制构造函数将被调用。换句话说,作为形参的对象,是用复制构造函数初始化的,而且调用复制构造函数时的参数,就是调用函数时所给的实参。
- 友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
- 用字符串作为参数输入时参数名称写(const char* p)
- 静态成员变量只能在类外进行初始化,形式为(数据类型) 类名:: 变量名 = 数据
注意初始化时候没有static - 静态成员变量调用的时候用类名进行调用类名::变量名
- 常成员函数不能修改对象的成员变量,可以修改类的静态成员变量
- 静态成员函数不能加上const
- 将普通函数参数为(const CLASS &)在类内声明为friend,可以将其设置为友元函数,可以访问对象的私有成员变量,若在类内直接定义函数,仍属于友元函数,直接调用函数即可,不需要通过类来访问
- 下面是不可重载的运算符列表:
- .:成员访问运算符
- .*, ->*:成员指针访问运算符
- :::域运算符
- sizeof:长度运算符
- ?::条件运算符
- #: 预处理符号 - 构造函数不能被继承,但是可以被调用。派生类的构造函数在初始化列表中应调用基类的构造函数。
- 基类private在派生类中不可访问
构造函数的调用顺序规则如下所述。
1 )基类构造函数。如果有多个基类,则构造函数的调用顺序是某类在类派生表中出现的顺序,而不是它们在成员初始化表中的顺序。
2 )成员类对象构造函数。如果有多个成员类对象,则构造函数的调用顺序是对象在类中被声明的顺序,而不是它们出现在成员初始化表中的顺序。
3 )派生类构造函数而析构函数的调用顺序与构造函数的调用顺序正好相反,将上面3 点内容中的顺序反过来用就可以了,即:首先调用派生类的析构函数; 其次再调用成员类对象的析构函数;最后调用基类的析构函数。析构函数在下面3 种情况时被调用。
132. 如果多重继承的数据成员或者成员函数同名,需要在数据成员名称和函数名称前加上域作用符,不然会由于二义性报错