在iOS开发过程中,有时候会用到一些C++的库,为了避免大家用到这种库的时候一脸懵逼,这里总结一些基础知识,不写C++没关系,起码当库出了什么问题的时候至少能看懂逻辑(或许吧)。
这里全部都是基础语法知识,没事的时候可以看看熟悉一下。
指针和引用 略
还是简单说一下:.
是对象访问属性的操作符,->
是指针访问指针属性的操作符,(*a).b
=>a->b
权限访问 public: 可以被任意实体访问
protected:只允许子类及本类的成员函数访问
private:只允许本类的成员函数访问
函数 默认参数 跟Swift差不多
1 2 3 4 5 int func (int a , int b = 10, int c = 10) ; // 声明中有默认参数,实现中不能有默认参数,比如下面这么写就会报错int func (int a , int b = 10, int c = 10) { return a + b + c; }
占位参数(没啥用) 1 2 3 4 5 void func (int a,int = 0 ) { cout << a << endl; } func (1 ,2 );
其实主要是用与兼容C语言的不规范写法,因为在C语言中,传参个数可以比函数声明的参数个数还多,比如func(1,2,3,4,5)
,会警告但是不会报错,但是C++这么写就会报错,所以为了兼容C语言的调用方式,就用占位参数,占个位但是不用它,这样子就不会报错。
函数重载 同一个作用域,函数名相同,参数个数不同/类型不同/顺序不同
函数的返回值不可以作为函数重载的条件
语法 1 2 3 4 5 6 void func () {}void func (int a) {}void func (double a) {}void func (int a, double b) {}void func (double a, int b) {}int func () {}
特殊情况 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void func (int &a) { cout << "func(int &a)" << endl; } void func (cont int &a) { cout << "func(cont int &a)" << endl; } int a = 10 ;func (a); func (10 ); void func2 (int a) { cout << "func2(int a)" << endl; } void func2 (int a,int b = 10 ) { cout << "func2(int a, int b)" << endl; } func2 (10 );
struct 和 class 的区别 struct
默认权限为public
class
默认权限为private
构造函数和析构函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> class Person { public : Person () { cout << "默认构造函数:系统会默认生成" << endl; } Person (int age) { cout << "带参数构造函数,写了这个系统就不生成无参构造函数" << endl; this ->_age = age; } Person (int age) : _height(15 ) { cout << "初始化部分参数的构造函数" << endl; this ->_age = age; } Person (int age, int height) : _height(height) { cout << "初始化部分参数的构造函数,并且顺便赋值了_height属性" << endl; this ->_age = age; } Person (const Person &person) { cout << "浅拷贝函数:系统会默认生成" << endl; } ~Person () { cout<<"析构函数:系统默认生成" <<endl; } int _age; int _height; SomeClass property; }; int main () { Person p1; Person p2 (11 ) ; Person p3 (11 ,160 ) ; return 0 ; }
链式调用函数 在上面的Person类内加多这么一个方法
1 2 3 4 5 6 7 8 9 Person& addAge (Person &p) { this ->_age += p._Age; return *this ; } Person pp (20 ) ;Person pp2 (10 ) ;pp.addAge (pp2).addAge (pp2).addAge (pp2);
静态方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Person {public : static void func () { cout << "静态方法只能访问静态常量" << test << endl; } static int test; }; int main () { Person p; p.func (); Person::func (); return 0 ; }
常函数和常对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <string> class Person {public : void funcA () const { this ->_age = 1 ; } string _name; mutable int _age; void funcB () { } } int main () { const Person p; p.funcA (); reutrn 0 ; }
在类外部实现函数 1 2 3 4 5 6 7 8 9 10 11 12 13 class Person {public : Person (); void test () ; }; Person::Person () { } void Person::test () {}
友元函数 友元函数可以访问被private
修饰的属性
全局函数做友元 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Building { friend void visitor (Building &building) ; public : Building () { m_SittingRoom = "客厅" ; m_Bedroom = "卧室" ; } string m_SittingRoom; private : string m_Bedroom; }; void visitor (Building &building) { cout << "全局函数" << building.m_SittingRoom << endl; cout << "全局函数" << building.m_Bedroom << endl; }
顺带一提:如果入参是引用的话(&building
),那么可以直接通过点语法访问成员属性,如果入参是指针的话(*building
),那么就通过->
访问,如(building->m_Bedroom)
顺带再提,两种函数声明和调用方式的不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void visitor (Building &building) { cout << "全局函数" << building.m_SittingRoom << endl; } void visitor2 (Building *building) { cout << "全局函数" << building->m_SittingRoom << endl; } int main () { Building building; visitor (building); visitor2 (&building); }
友元类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Building { friend class Visitor ; public : Building () { m_Bedroom = "卧室" ; } private : string m_Bedroom; }; class Visitor { public : Visitor () { building = new Building; } void visit () ; Building *building; }; void Visitor::visit () { cout << building->m_Bedroom << endl; } int main () { Visitor v; v.visit (); return 0 ; }
成员函数做友元函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Building ;class Visitor { public : Visitor (); void visit () ; Building *building; }; class Building { friend void Visitor::visit () ; public : Building () { m_Bedroom = "卧室" ; } private : string m_Bedroom; }; Visitor::Visitor () { building = new Building; } void Visitor::visit () { cout << building->m_Bedroom << endl; } int main () { Visitor v; v.visit (); return 0 ; }
运算符重载 跟Swift差不多
成员函数的运算符重载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Animal {public : Animal operator + (Animal &a) { Animal temp; temp.m_A = this -> m_A + a.m_A; return temp; } int m_A; }; Animal a; a.m_A = 1 ; Animal b; b.m_A = 2 ; Animal c = a + b; cout << c.m_A << endl;
本质:Animal c = a.operator+(b);
全局函数的运算符重载 1 2 3 4 5 6 7 8 9 10 11 12 Animal operator - (Animal &a, Animal &b) { Animal temp; temp.m_A = a.m_A - b.m_A; return temp; } Animal a;a.m_A = 1; Animal b;b.m_A = 2; Animal c = a - b;cout << c.m_A << endl; // 输出 -1
本质:Animal c = operator-(a,b);
运算符重载也可以发生函数重载 1 2 3 4 5 6 7 8 9 Animal operator + (int a, Animal &b) { Animal temp; temp.m_A = a + b.m_A; return temp; } Animal a; a.m_A = 1 ; Animal d = 10 + a; cout << d.m_A << endl;
本质:Animal d = operator+(10,a);
左移运算符重载(比较常见输出对象细节) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class MyInteger { friend ostream& operator <<(ostream& cout,MyInteger myInt); public : MyInteger () { this ->my_int = 0 ; } private : int my_int; }; ostream& operator <<(ostream& cout,MyInteger myInt) { cout << myInt.my_int; return cout; } int main () { MyInteger myInt; cout << myInt << endl; return 0 ; }
关系运算符重载 Swift经常使用,参见Equable
,Comparable
协议
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Person { public : bool operator ==(Person &p) { if (this ->m_Name == p.m_Name) { return true ; } return false ; } bool operator !=(Person &p) { if (this ->m_Name != p.m_Name) { return true ; } return false ; } string m_Name; }; int main () { Person p1; p1.m_Name = "A" ; Person p2; p2.m_Name = "A" ; if (p1 == p2) { cout << "Equal" << endl; } else { cout << "Different" << endl; } if (p1 != p2) { cout << "Different" << endl; } else { cout << "Equal" << endl; } return 0 ; }
函数调用运算符的重载(骚操作) 因为用起来很像函数,所以又叫做仿函数,STL里相当多这种骚操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class MyInteger { int operator () (int a,int b) { return a + b; } }; int main () { int result = MyInteger ()(1 ,2 ); MyInteger i; int result2 = i (5 ,2 ); cout << result << endl; cout << result2 << endl; }
继承 C++有多继承,灰常厉害
继承方式 三种继承方式public
,protected
,private
,决定着继承下来的属性和方法以什么形式修饰,class
默认private
,struct
默认public
(没错,C++中结构体可以被继承) 父类的所有非静态属性会被继承,包括private
类型的,但是private
类型的默认隐藏,子类无法访问。
继承语法:
1 2 3 class SubClass : public SuperClass {};
构造和析构 父类先构造,子类先析构
1 2 3 4 superClass () subClass () ~subClass() ~superClass()
同名属性/函数/静态属性/静态函数的访问 假如子类和父类拥有相同的名字的属性/函数/静态属性/静态函数,则直接调用子类对象的话都是访问子类的,如果要访问父类的话要添加作用域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 class Base {public : int _a = 1 ; static int _b; static void staticFunc () { cout << "Base staticFunc()" << endl; } void Func () { cout << "Base Func()" << endl; } }; int Base::_b = 10 ; class Sub1 : public Base {public : int _a = 2 ; static int _b; static void staticFunc () { cout << "SubClass staticFunc()" << endl; } void Func () { cout << "SucClass Func()" << endl; } }; int Sub1::_b = 20 ;int main () { Sub1 s; cout << s._a << endl; cout << s.Base::_a << endl; cout << s._b << endl; cout << s.Base::_b << endl; cout << Sub1::_b << endl; cout << Sub1::Base::_b << endl; s.Func (); s.Base::Func (); s.staticFunc (); s.Base::staticFunc (); Sub1::staticFunc (); Sub1::Base::staticFunc (); return 0 ; }
多继承 不建议使用,因为麻烦事多
语法:(参照上面的代码)
1 2 3 4 5 6 7 8 9 10 class Other {public : void Func() { cout << "Ohter Func()" << endl; } }; class Sub1 : public Base , public Other {}
当多个父类中出现同名属性/方法时,需要加作用域指定父类s.Base::Func(); / s.Other::Func();
菱形继承(钻石继承) 两个子类继承同一个基类, 又有某个类同时继承着两个子类
举例
1 2 3 4 5 6 class Base { int age };class Sub1: public Base {};class Sub2: public Base {};class SubSub: public Sub1, public Sub2 {};
这时候SubSub会有两个父类,有两份 age 属性,造成资源浪费
这时候用虚继承(virtual
)解决问题
1 2 3 4 5 6 class Base { public : int age }; class Sub1: virtual public Base {};class Sub2: virtual public Base {};class SubSub: public Sub1, public Sub2 {};
这时候age属性成为共享属性,最后谁改了就是谁的值
1 2 3 4 5 6 SubSub s; s.Sub1::age = 1 ; s.Sub2::age = 10 ; cout << s.Sub1::age << endl; cout << s.Sub2::age << endl; cout << s.age << endl;
多态 C++中,多态分两类
静态多态:函数重载和运算符重载属于静态多态,复用函数名 动态多态:子类和虚函数实现运行时多态
区别:
静态多态的函数地址早绑定,编译阶段确定函数地址 动态多态的函数地址晚绑定,运行阶段确定函数地址
动态多态满足条件:
有继承关系
子类重写父类虚函数
动态多态使用 父类的指针或者引用指向子类对象
静态多态举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Animal {public : void speak () { cout << "Animal Speak" << endl; } }; class Cat : public Animal{ public : void speak () { cout << "Cat Speak" << endl; } }; void SomeoneSpeak (Animal &animal) { animal.speak (); } int main () { Cat c; SomeoneSpeak (c);
如果想输出Cat Speak
,只需进行如下修改
1 2 3 4 5 6 class Animal {public : virtual void speak () { cout << "Animal Speak" << endl; } };
经常地,这种情况下也是动态多态,最后会输出Cat Speak
1 2 Animal *a = new Cat a->speak()
纯虚函数和抽象类 父类的虚函数的实现没什么意义,所以上面的虚函数代码改写为纯虚函数
1 virtual void speak () = 0 ;
当类中有了纯虚函数,则这个类称为抽象类
抽象类无法实例化对象 ,并且子类必须重写父类的纯虚函数 ,否则也成为抽象类
虚析构和纯虚析构 当子类在堆区创建数据的时候,需要手动释放,父类需要添加虚析构或者纯虚析构函数,否则子类可能不走析构函数
比如上面的Animate
父类,我们补充一下
1 2 3 4 5 6 7 8 class Animal {public : virtual ~Animal () = 0 ; }; Animal::~Animal () { cout << "Animal is Delete" << endl; }
文件操作 文件打开方式
ios::in
:读文件ios::out
:写文件ios::ate
:初始位置,文件尾ios:app
:追加写文件ios:trunc
:如果文件存在先删除,再创建ios:binary
:二进制方式
同时两种方式则使用|
的方式,比如ios::in|ios:binary
写文件 1 2 3 4 5 6 7 8 9 10 ofstream stream; stream.open ("Test.txt" ,ios::out); stream << "Line 1" << endl; stream << "Line 2" << endl; stream << "Line 3" << endl; stream.close ();
读文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ifstream ifs; ifs.open ("Test.txt" ,ios::out); if (!ifs.is_open ()) { cout << "打开文件失败" << endl; return 0 ; } string buf; while (getline (ifs, buf)) { cout << buf << endl; } ifs.close ();
类模板 构建类模板与类模板做参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template<class NameType,class AgeType > class Person {public : Person(NameType name, AgeType age) { this ->_age = age; this ->_name = name; } AgeType _age; NameType _name; }; int main() { Person<string ,int > p("Haha" ,123 ); cout << p._name << " " << p._age << endl; return 0 ; }
可以给类模板添加默认类型
template<class NameType,class AgeType = int>
这样子调用的时候就可以不全声明类型了
Person<string> p("Haha",123);
类模板做参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void print(Person<string ,int > &p) { p.showPerson(); } template<class T1,class T2 > void print2 (Person <T1, T2 > &p ) { p.showPerson(); } template<class T > void print3 (T &p ) { p.showPerson(); } int main() { Person<string ,int > p("Haha" ,123 ); print(p); print2(p); print3(p); return 0 ; }
类模板与继承 继承时需要指定类型
1 2 3 4 5 6 7 8 9 10 11 12 13 template<class T > class Base { public : T m; }; class SubClass: public Base <int > { public : void print() { cout << m << endl; } };
如果不想指定类型,那么可以模板化子类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template<class T > class Base { public : T m; }; template<class T1,class T2 > class SubClass: public Base <T1 > {public : SubClass(T1 a, T2 b) { } T2 k; }; int main() { SubClass<string , int > c("String" ,1 ); return 0 ; }
STL 之 Vector容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 vector<int > v1; v1.assign (10 , 1 ); for (vector<int >::iterator i = v1.begin (); i != v1.end () ; i++) { cout << *i << endl; } cout << "Size = " << v1.size () << endl; cout << "isEmpty = " << v1.empty () << endl; cout << "capacity = " << v1.capacity () << endl; v1.resize (20 ,20 ); cout << "capacity = " << v1.capacity () << endl; v1.pop_back (); cout << "Size = " << v1.size () << endl; cout << "capacity = " << v1.capacity () << endl; v1.insert (v1.begin () + 1 , 199 ); v1.insert (v1.begin () + 1 , 2 , 199 ); v1.erase (v1.begin () + 2 ); v1.erase (v1.begin () + 2 , v1.begin () + 3 ); v1.clear (); cout << "第二个元素是" << v1.at (1 ) << endl; cout << "第三个元素是" << v1[2 ] << endl; cout << "第一个元素" << v1.front () << endl; cout << "最后一个元素" << v1.back () << endl; v1.reverse (100000 ); v1.swap (v0);