变量可用表达式初始化
{}内部作用域,可定义与外部变量同名的变量。内部变量隐藏了外部变量(新定义的变量说了算)
在for循环中可以定义局部变量,作用于for循环这一内部作用域
在函数内部,想要访问和内部变量同名的全局变量,可使用全局作用域限定"::"
eg:cout<<::a<<endl; //输出全局变量a
引用,不涉及将实参拷贝给形参(传值),无额外内存开销,效率高,尤其当实参占据很大内存时
想提高效率,又不希望形参的修改影响实参,可以将形参类型写为const int& x,就无法在子函数中对其进行修改了
inline(在函数最前方加上该关键字)内联函数,为了解决频繁调用小函数,占用大量栈空间的问题。将函数调用,替换成函数中的简单语句,以提高程序执行效率。
小函数中不能包含复杂的结构控制语句,且不能递归(程序调用自身),编译器才会将内联函数,内联展开
try-catch处理异常情况,正常代码放在try块,catch中捕获try块抛出的异常
throw,抛出异常对象,在try块中throw后,try块中其余的代码就都不会执行了
catch(...){...},万能接盘侠,接收之前没被捕获到的异常
try{
if(num>50) throw 1;
if(num<50) throw 1;
throw "hello";
}
catch(int result){ //这个catch块只能捕获到整形异常。字符串类异常可用const char* s来捕获
...
}
重载,分为函数重载(类型或个数不同)、运算符重载。允许在同一作用域中,为函数和运算符指定多个定义。
运算符重载,当用户自定义类型使用运算符时,需进行运算符重载。
编译器转换成的函数形式:operator<<(cout,m); //其中m为Man类型
声明模板类型参数时,typename全面优于class
当T是一个类,且这个类有子类时,应该用template <typename T>。
typename T::innerClass myInnerObject,此时不能用class。typename告诉编译器,T::innerClass是一个类innerClass是T的子类,程序要声明一个T::innerClass类的对象,而不是声明T的静态成员innerClass。
template<typename T1,typename T2>
T1 findMin(T1 a, T2 b) { //T1整形,T2浮点型
if (a<b)
{
return a;
}
return /*(T1)*/b;
}
C语言中,void* calloc(int a,int b);void* malloc(int a);void* realloc(void* a,int b)
malloc,开辟a个字节;不进行初始化;需要强转
calloc,开辟a*b个字节;初始化成ASCII值为0(NULL);需要强转
realloc,①若指针a所指空间的后面,有足够的空间增加至总共b个字节,则直接扩充;②若空间不够,则开辟新空间+复制过去+释放旧空间+返回指向新空间的指针;需要强转。参数a必须是动态开辟的地址,不能是静态定义的数组的地址。
强制类型转换,限定了步长
C++中,new与delete,对类对象调用了构造函数与析构函数
可以直接new一个动态数组,eg:n=8; double* p=new double[n];
#define _CRT_SECURE_NO_WARNINGS,Windows系统下使用
类(class),在C语言struct基础上,增加了成员函数,现两者皆可
成员函数的自引用,"return *this;(返回自身的引用)"使该成员函数可以串起来连续使用,eg:d.add(2).add(3)
Date& add(int i){
day=day+i; //increment,n.增量[数]
return *this; //this是指向调用这个函数的(类的)对象的指针 //*this是调用这个函数的那个对象
}
在类中成员函数的重载
重载运算符+=时,应注意运算符优先级中的结合方向,为从右向左,故(d += 3) += 5;,否则从右向左时,3是常量(err:表达式必须是可修改的左值)
在构造函数的形参中,给所有成员变量赋初值,就可以在少参和无参时定义变量了
eg:Date day、Date day(2021)、Date day(2021,9)、Date day(2021,9,26)皆可
可以在构造函数中,分配内存、打开文件、打开网络端口等
可以在析构函数中,将内存还给操作系统,关闭文件,关闭网络端口等
间接访问private成员,写一个get_...的函数。
public:
char* get_name() {return name;} //写函数
stu.get_name() //间接访问
同理,间接修改private成员,写一个set_...的函数。释放原来空间,再开辟,拷贝。
void set_name(char* n="new_name") //修改不需要返回值 //可以提供默认参数,以应对不提供参数的情况
"public:"部分,称为这个类对外界公开的接口
拷贝,分为①拷贝构造函数(定义一个类对象时,用同类型的另外对象对其进行初始化),和②赋值运算符(一个对象赋值给另一个对象)。
即student s(m);,和m=n;
虽然编译器会自动生成这两个东西,但因为Student类中的成员变量涉及到内存分配,所以使用默认的拷贝构造函数会出错,故需要重载相应的拷贝构造函数与赋值运算符。
在类外定义成员函数,在类内声明+在类外加上类的作用域(eg:void Date::print() {...}),说明print()不是全局函数,而是该类的成员函数。
用模板类时,要写上类模板的<参数列表>。即在内部有template类型变量的类后加上尖括号,并在里面写上变量类型,eg:Array<double> arr;
cerr,eg:cerr<<endl<<...<<endl;
typedef用途,typedef int(或long) INT,可以使不同操作系统下INT的字节数相同
string的API:
(1)string("...",6);,取字符串"..."中的前6个字符构成新字符串
(2)string("...",4,6);,从字符串"..."下标为4的字符开始,往后取6个字符构成新字符串
(3)string(6,'*');,一个由6个*号构成的字符串
(4)string(s4.begin(),s4.end()-3);,s4.begin()指向开头字符,s4.end()指向结尾字符'\0',两者都是指针,截取两者之间的那段字符串。string(start iterator迭代器,end iterator)
s.size(),字符串s的字符个数
(5)...+...,将2个字符串相连
用字符串迭代器遍历字符串:,迭代器变量是一个指针
string s = "helloworld!";
//string::const_iterator ci; //常量迭代器,不可以修改字符(不能给常量赋值)
string::iterator ci; //普通迭代器,可以修改字符
int i = 0;
for (ci = s.begin(); ci != s.end(); ci++){
*ci = 'a';
cout << i << " " << *ci << endl;
i++;
}
size_type和size_t:
size_type,机器不同长度不同,使得程序与机器相匹配,size_type是string类和vector类定义的类,用于保存string对象和vector对象的长度,标准库类将size_type定义为unsigned类型;
size_t,增强程序在不同平台上的可移植性,C/C++标准只定义了变量类型的相对关系,没有固定各类型的具体大小,各系统在内存中又分为高位对齐存储和低位对齐存储。
常函数和常对象:
常函数(函数被调用,函数内部的操作),①常函数能被普通对象或常对象调用,②常函数不能“写”普通成员变量,除非有mutable(a.可变的)关键词修饰
常对象(调用函数,对象的操作),①常对象只能调用常函数,不能调用普通函数②常对象只能读成员变量
inheritance继承(derivation派生),一个derived class派生类,从一个或多个parent class父类/base class基类继承,继承父类的属性和行为,但其也有自己的特有属性和行为
eg:class Manager : public Employee{...}; //public,private,protected
初始化成员列表,Employee::Employee(string n) :name(n) {},Manager::Manager(string n, int l) :Employee(n), level(l) {}
通过调用基类的print函数,以实现输出派生类成员变量+父类(基类)成员变量
void Manager::print() {
cout << "L" << level << " "; //既输出了经理的级别
Employee::print(); //又输出了雇员的名字
}
基类指针可以指向派生类对象,反之派生类指针无法指向基类对象。故可以用一个指向基类的指针,分别指向基类对象和派生类对象
多态,基类函数前加virtual,基类指针会根据实际指向的对象类型,调用相应的函数。
只有当一个类作为基类的时候,才会把函数变成虚函数,以实现多态。
virtual关键字加在析构函数之前,声明成虚函数。虚析构函数,使得派生类申请的空间也会得到释放,防止内存泄露。
多重继承(派生derivation)Multiple inheritance,多个类派生出一个类
当然,一个类可以派生出多个类
纯虚函数pure virtual function,函数体=0的虚函数,eg:virtual const char* speak()=0;
抽象类abstract base class,包含纯虚函数的类,抽象类不能实例化(不能创建对象)。从抽象类派生的类如果没有继承实现所有的纯虚函数,则仍然是抽象类。反之若将纯虚函数都实现了,就不是抽象类了,就能创建对象了。
抽象类通常作为接口,不涉及到具体实现