头文件-注释-名字空间
#include <cstdio>//不用 <*.h>形式
#include <iostream>//输入输出流
using namespace std;//标准库的名字空间
using X::name;//使用X名字空间的单个名字name
名字空间 namespace
namespace first {
int a;
void f(){/**/}
}
int main() {
first::a = 3;//使用first名字空间
}
输入输出流
#include <iostream>
using namespace std;
int main(){
int n;
cin >> n;//输入
cout << "Hello World!" << endl;//输出
return 0;
}
变量及其作用域
- 变量可以随时定义
- { }表示一个作用域,在这个程序块中的变量是局部变量
- ::a 表示在局部作用域里访问全局同名变量a
引用
类似C语言的指针用法,引用符**&** 给一个变量起了另一个名字,在函数中被引用的形参与实参是同一个变量,可以在函数中被修改。
内联函数和异常处理
内联函数
-
函数定义前面加上 inline 关键字,如
inline int distance(}{/**/}
-
内联函数用于不含循环的函数,在被调用时直接用函数体替换。没有形参与实参的传递开销。
异常处理
-
通过 try - catch 处理异常情况,正常代码放在try块,catch中捕获try块抛出的异常。
try { if (a > 100) throw 100; if (a < 10) throw 10; throw a / 3; } catch (int result) { cout << "Result is:" << result << endl; } catch(...) { cout << "其他所有异常都在这里捕获" << endl; }
-
实际编程中少用
函数的默认参数
-
默认形参,必须一律在最右边
double test(double a, double b = 7){/**/}
函数重载、运算符重载
函数重载
- C++允许函数同名,只要它们的形参不一样(个数或者对应参数的类型)
- 调用函数时将根据实参和形参的匹配选择最佳函数,如果有多个难以区分的最佳函数,则变化一起报错!
- 不能根据返回类型区分同名函数
运算符重载
ElemType operater +[-*/] (ElemType a, ElemType b) {
/**/
return result;
}//重新定义特殊类型的运算符,比如向量的点乘、叉乘、数乘。
模板函数 template
- 模板template函数:厌倦了对每种类型求最小值(针对同一功能,要满足多种数据类型)
template<class Type>//Type为一个模板类型
Type minValue(Type a, Type b) {
if (a < b) return a;
else return b;
}
//自动生成一个针对该数据类型的具体函数
-
不同类型参数
template<class Type1, class Type2> Type1 minValue(Type1 a, Type2 b) { if (a < b) return a; else return (Type1)b; }
动态分配内存的new 和 delete
- new 对应 malloc
- delete 对应 free
dp = new double;//返回一个指向double类型的指针
delete dp;//释放一个double大小的内存
dp = new double[n];//新建一个指向一块double类型的内存,并返回首地址指针
delete[] dp;//释放一整块内存
类的定义
-
类是在C的struct类型上,增加了成员函数。
-
C++使得struct不但包含数据,还包含函数(方法)用于访问或修改类变量(对象)的特性。
struct date { int year,month,day; void print() { cout << year << '-' << month << '-' << day << endl; } }//这是一个简单的C++类
自引用、成员函数重载运算符
自引用
-
成员函数返回“自引用” (*this)
struct date { int year,month,day; void print() { cout << year << '-' << month << '-' << day << endl; } date & add(int d) { day = day + d; return *this;//this是指向调用这个函数的类型对象指针 //*this就是调用这个函数的那个对象 //这个成员函数返回的是“自引用”,即调用这个函数本身 //通过返回自引用,可以连续调用这个函数 //Day.add(3); //Day.add(2).add(7); } }
成员函数重载运算符
struct date {
int year,month,day;
void print() {
cout << year << '-' << month << '-' << day << endl;
}
date & operator+=(int d) {
day = day + d;
return *this;//this是指向调用这个函数的类型对象指针
//*this就是调用这个函数的那个对象
//这个成员函数返回的是“自引用”,即调用这个函数本身
//通过返回自引用,可以连续调用这个函数
//Day.add(3);
//Day.add(2).add(7);
}
}
构造函数和析构函数
构造函数
struct date {
int year,month,day;
void print() {
cout << year << '-' << month << '-' << day << endl;
}
date(int dd,int mm,int yy) {
day = dd;
month = mm;
year = yy;
}//类似的函数名字与类名一致,并且没有返回类型的函数,称为构造函数。
//构造函数在我们定义一个类的对象时,会被自动调用。
}
析构函数
struct date {
int year,month,day;
void print() {
cout << year << '-' << month << '-' << day << endl;
}
date(int dd,int mm,int yy) {
day = dd;
month = mm;
year = yy;
}//类似的函数名字与类名一致,并且没有返回类型的函数,称为构造函数。
//构造函数在我们定义一个类的对象时,会被自动调用。
virtual ~date() {//析构函数不需要参数
delete[] name;//析构函数释放之前申请的内存,防止内存泄漏
}
}
访问控制与接口
- 将struct类型改为class类型(class定义的类的成员默认都是私有的private,外部函数无法通过类对象成员或类成员函数)
- 想要在class中定义可以控制的接口,需要加上关键字 public: 表示公开的。
- 若要改变private的成员,需要在接口处定义函数修改。
- 接口:public的公开成员,(一般是成员函数),称为这个类的对外接口,外部函数只能通过这些类接口访问类对private等非public的包含内部细节,不对外公开,从而可以封装保护类对象。
拷贝构造函数和赋值运算符
-
拷贝构造函数:定义一个类对象时用同类型的另外对象初始化
struct student{/**/} student a; student b(a);//b是拷贝构造函数,默认的拷贝构造函数是一种硬拷贝,并没有新分配内存 //遇到多次析构函数会报错 //解决办法是在结构体中自定义拷贝构造函数,
-
赋值运算符:一个对象赋值给另一个对象
类体外定义成员函数(方法)
-
必须在类定义中声明,类体外要有类作用域,否则就是全局外部函数了!
class student { public: void print();//在类体内只声明 } void student::print() {//在类体外定义时加上类作用域 cout << "Hello World!" << endl; }
类模板
-
我们可以把一个类变成一个“类模板”或“模板类”,正如一个模板函数一样。
-
例如:将原来所有的double换成模板类型Type,并加上模板头 template
template <class T> class Array { int size; T *data; } int main(){ Array<double> t[10];//用double代替类模板里的T Array<string> s[10]; }
类型别名typedef
typedef int INT
String和Vector、继承与派生、虚函数和纯虚函数
-
string对象的初始化
#include <iostream> #include <string> using namespace std; int main() { string s1; string s2("hello"); s1 = "Hello"; string s3(s1);//拷贝构造函数, string s3 = s1; string s4("This is a C_string",10);//取前10个字符构成字符串 string s5(s4,6,4);//从s4中第6个字符开始取4个构成字符串 string s6(10,'*');//由15个‘*’构成的字符串 string s7(s4.begin(),s4.end() - 5); string s8 = "Hello"; string s9 = s1 + "hello" + s2; }
-
string对象的长度: s.size()
-
vector
#include <vector> #include <iostream> using namespace std; int main() { vector<double> student_marks; student_marks.resize(10);//此语句用于重新定义向量的大小,默认为0 for (vector<double>::sizetype i = 0; i < num_students; i++) {/**/}//赋值 //vector<double>::sizetype i 更安全 for (vector<double>::iterator it = student_marks.begin(); it != student_marks.end(); it++) { cout << *it << endl; } return 0; }
派生类
-
Inheritance继承(Derivation派生):一个派生类(deived class)从1个或多个父类(parent class) / 基类(base class)继承,即继承父类的属性和行为,但也有自己的特有属性和行为。
class Employee {/**/} class Manager: public Employee {/**/}//Manager继承了Employee的类,但也有自己特有的属性
-
初始化成员列表
Employee::Employee(string n):name(n){} //表示传入一个参数n,并将n赋值给成员name Manager::Manager(string n; int l):Employee(n),level(l){} //给基类Emlpoyee传入n参数,将l赋值给level成员
-
派生类的构造只能描述它自己的成员和其直接基类的初始式,不能去初始化基类的成员
虚函数和多态
- 派生类的指针可以自动转化为基类指针,用一个指向基类的指针分别指向基类对象和派生类对象,因此,可以把所有基类以及派生类的对象的指针都放在一起便于管理
- 基类和派生类的同名函数有不同的功能时,需要在基类中该函数前加上关键字 virtual 表示为虚函数,(派生类可加可不加),这样就可以根据不同的指针调用不同派生类中的不同函数,产生的现象叫 多态性 。
多重继承和多重派生
-
我们可以从一个类派生出多个不同的类
-
也可以从多个不同的类派生出一个类,多重派生
class one{} class two{} class mul:public one,public two
纯虚函数和抽象类
-
纯虚函数(pure virtual function)和 抽象类(abstract base class)
-
函数体=0的虚函数称为纯虚函数。包含纯虚函数的类称为抽象类。
virtual const char * speak() = 0;//speak()是一个纯虚函数
-
抽象类不能实例化(不能定义抽象类的对象/变量)
-
从抽象类派生的类型如果没有继承实现所有的纯虚函数,则仍然是抽象类
class Cow:public Animal { public: Cow(std::string name):Animal(name){} virtual const char* speak(){return "Moo";}//实现了纯虚函数,不再是抽象类 }
-