第一章 C++标准与C
C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制)。
C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。
所以C与C++的最大区别在于它们的用于解决问题的思想方法不一样。之所以说C++比C更先进,是因为“ 设计这个概念已经被融入到C++之中 ”。
1.命名空间
namespace 关键字使得我们可以通过创建作用范围来对全局命名空间进行分隔。本质上来讲,一个命名空间就定义了一个范围。定义命名空间的基本形式如下:namespace 名称{//声明} ----- 使用: using namespace 名称
c++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。 因此,当使用
2.标准的输入输出
#include
#Include
3.动态分配内存与释放
创建 指针变量=(类型强转)malloc(size)
创建 指针变量 = new 数据类型 释放 delete指针
4.函数
函数添加const 缺省函数参数
缺省参数是在编译期决定的,但确定引用、指针的虚函数调用类型是在函数运行的时候。
5.引用
引用是C++语言的一个特殊的数据类型描述,用于在程序的不同部分使用两个以上的变量名指向同一地址,使得对其中仁义比那两的操作实际上都是对同一地址单元进行的。在这种两个以上变量名的关系上,被声明为引用类型的变量名则是实际变量名的别名。
注意:对引用进行操作,实际上时对被引用的变量进行操作;引用不是值,不占存储空间,声明引用时,目标的存储状态不会改变;引用一旦被初始化,就不能再重新引用其他空间;区分地址符和引用符。
引用经常为函数的参数,作为指针变量的引用来使用。
常引用声明方式:const 类型标识符&引用名=目标变量名;用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。
【例】:
int a ;
const int &ra=a;
ra=1; //错误
a=1; //正确
这不光是让代码更健壮,也有些其它方面的需要。
【例】:假设有如下函数声明:
string foo( );
void bar(string & s);
那么下面的表达式将是非法的:
bar(foo( ));
bar("hello world");
原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。
引用型参数应该在能被定义为const的情况下,尽量定义为const 。
6.其他
作用域运算符 ::
增强型的for循环:
类与结构体: C++结构体内部成员变量及成员函数默认的访问级别是public,而c++类的内部成员变量及成员函数的默认访问级别是private。C++结构体的继承默认是public,而c++类的继承默认是private。
第二章 类与对象
面向对象的编程(OOP)是一种特殊的、设计程序的概念性方法,C++通过一些特性改进了C语言,使得应用这种方法更容易。
最重要的OOP特性: 封装和数据隐藏; 多态; 继承; 。
封装: 隐藏实现细节;恰当地公开接口;将接口和实现分开,增强可维护性;(实现细节改变时,使用该类的客户端程序不需要改变)
继承:描述联结类的层次模型; 通过抽象,表达共性,实现类的重用; 通过子类增加方法和属性以及重写方法,表达差异性;
多态:屏蔽子类的差异性,针对共性/接口编程 (向上转型);增强可扩展性;
1.类和对象
类是一组具有相同属性和行为对象的抽象
给类申请空间的时候,只申请成员数据(或成员属性)大小的空间;而类的函数在代码区
访问修饰符(数据访问,继承) private 本类 protected本类和子类 public公共
2.构造函数
创建对象时执行的,给类的成员属性初始化;如果没有写,系统会给一个空的
3.析构函数
当对象声明周期结束时,其所占有的空间被回收;析构函数无参数无返回值
4.this指针
一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。
5.copy构造函数 默认给一个浅拷贝
浅拷贝:两个指针指向同一块空间B(B b) 同一块空间可能会释放两次
深拷贝:重新申请一块空间,两个指针指向两块空间,然后进行复制B(B& b) B(B* b)
使用指针和引用都不会执行拷贝构造函数;当函数数值传递对象或函数返回对象时,都将使用拷贝构造函数。
6.接口类和抽象类
抽象类:定义了一个或多个纯虚函数的类。不能被实例化。
接口类:全都是纯虚函数的类。
7.友元
友元类:别人用自己的private成员属性。友元不能被继承。friend class A
友元函数:友元函数是能够访问类中的私有成员的非成员函数。 friend
Screen& Screen::copy(Window&);
8.操作符与类相关的数据类型不匹配时:首先选择重载运算符,次之选择类型转换。
(1)重载运算符:类内重载对象一定在左边;"="不能在类外重载。
类内:int operator++(); //++p int operator++(int a){ a=num; num=num+a; return a;}//p++
类外:ostream& operator<<(ostream& os,char* ch){os< 重载类型:无返回值类型无参数,但有返回值 operator bool() {return b;} CCPeople cp; bool bl = true; bl= cp; (2)类型转换: 关键字explicit不允许构造函数执行类型转换 CCPeople cp; CCPeople cp(); CCPeople cp= new CCPeople(); 9.定义一个空的C++类,例如 class Empty 一个空的class在C++编译器处理过后就不再为空,编译器会自动地为我们声明一些member function,一般编译过去就相当于 class Empty 10.临时对象的创建: 在使用临时对象(可能是无名对象或者对象值时)创建构造另一个对象的过程中,C++会优化掉该临时对象的产生;直接以相同参数调用相关构造函数或者直接调用拷贝构造函数到目标对象。 若不是对象创建,而是对象赋值,则赋值表达式的右值处的临时对象创建不能省略,临时对象赋值给左值后,表达式结束,临时对象被析构。 11.类的书写 头文件中 #pragram once #ifndef 防止重定义,属性声明,函数声明; 对应源文件 函数关键字不写,除const外,函数名前加类名,作用域运算符。 不要返回指向局部变量或临时对象的引用,函数后会释放。 class CPeople { public: int a; static const int ia= 30; const int b; static int c; public: CPeople(int i):b(i) { a=200; } void showA() { cclog("abc") }; void showB() const; static void showC(); }; int CPeople::c=300; => int main() { CPeople::showC(); //静态函数不访问非静态变量,可以被类和对象调用 const CPeople cp; //不能直接改变对象的值; //cp.showA(); //不能const CPeople &转换成CPeople & cp.showB();//可以调用,常函数不能直接改变属性的值 CPeople* const p=new CPeople; p->showA(); //P->showB(); } 12.重写 重载 隐藏 public AA { public: void show() {cout<<"AA"< void show(int a) {cout<<"AA"<
}; public BB: public AA { public: int show() {cout<<"BB"< }; int main() { //http://www.jb51.net/article/54225.htm //重载:重载从overload翻译过来,是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。 //隐藏:隐藏是指派生类的函数屏蔽了与其同名的基类函数。注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。无virtual关键字。 //重写:重写翻译自override,也翻译成覆盖(更好一点),是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。 } 13.继承-提高代码的重复性 通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。 单继承多继承: 先继承谁,就先执行谁的构造 CSon *p=new CSon; delete p; 父构造-子构造-子析构-父析构 CFather *p=new CSon; delete p; 调用父析构,不调用子析构;(基类使用虚析构,也调用子析构) 当子类中是无参的构造函数,但父类中是有参数的构造函数CSon():CFather(100){}。也可以从子类构造中传递给父类构造函数CSon(int num):CFather(num){} 子类构造函数要点:1首先创建父类对象;2.子类构造函数应通过成员初始化列表,将基类信息传递给基类的构造函数;3子类构造函数应初始化子类新增的数据成员。 CFather *p=new CFather; p->show(); ((*B)p)->show(); 虚继承: 解决在多继承中访问不明确关系的问题。根据虚继承的特性,虚基类的构造函数由最终的子类创建时负责构造。 假设derived 继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误; 假设derived 虚继承自base类,那么derivd与base是一种“has a”的关系,即derived类有一个指向base类的vptr。 class a{virtual void func();char x;}; class b:public virtual a{virtual void foo();}; 分别求sizeof(a), sizeof(b): 8, 16 (如果不是虚继承,会少一个虚类指针和虚指针:8,8) 14.多态 C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数, 而子类重新定义父类的做法称为覆盖(override).多态的好处,提高扩展性和代码重用性。 具有相同功能,但是每个功能的实现方式是不一样的函数,可以定义成虚函数(存在,内存,效率)。 类中无论有了多少个虚函数,继承多少层,只有一个虚指针,虚函数地址都装到虚函数列表中。虚指针是在定义对象的时候,放在对象的第一位置; 非public的虚函数,可以通过访问虚函数列表的方式去调用。 15.函数指针 class CFather { public: void AA() {cout << "CFather::AA" << endl;} }; class CSon : public CFather { public: void BB(){cout << "CSon::BB" << endl;} }; typedef void (*Fun)(); typedef void (CFather::*FUN_FATHER)(); typedef void (CSon::*FUN_SON)(); // --add class A { public: void AA(){cout << "A::AA" << endl;} }; int main() { //普通函数,静态成员函数使用 FUN fun = &CPeople::show(); (*fun)(); //普通成员函数使用,对象调用.* ->* //继承的函数指针 FUN_FATHER father = ( void (CFather::*)() )&CSon::BB; CSon* pb=new CSon; (pb->*father)(); //FUN_SON son= &CFather::AA; 指针可强转 //CFather a; //(a.*son)(); //函数指针实现多态 FUN _FATHER fun_father = (FUN_FATHER)&A::AA; CFather* p = new CSon; (p->*fun_father)(); //------------------------------- system("pause"); return 0; } 16.内部类 17.模板 容器 stl boost 类模板: 如果一个类中数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就必须将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表着一类类。 模板类是类模板实例化后的一个产物。 函数模板:可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计。它的最大特点是把函数使用的数据类型作为参数。模板函数的生成就是将函数模板的类型形参实例化的过程 //#include
{
}
{
public:
Empty(); // 缺省构造函数
Empty( const Empty& ); // 拷贝构造函数
~Empty(); // 析构函数
Empty& operator=( const Empty& ); // 赋值运算符
Empty* operator&(); // 取址运算符
const Empty* operator&() const; // 取址运算符 const
};
//using namespace std;
//
//
//template
//class CFather
//{
//private:
// T t;
//public:
// CFather(T a):t(a) //初始化列表处不可以用 this->t=t---------------
// {
// //this->t=t;
// }
// void show()
// {
// cout<
//};
//
//template
//class CSon:public CFather
//{
//private:
// X x;
//public:
// CSon(T t,X x):CFather
// {
// this->x=x;
// }
// void show()
// {
// cout<
//};
//
//template
//class A
//{
//private:
// W w;
//public:
// A(W ww)
// {
// this->w=ww;
// }
//};
//template
//ostream& operator<<(ostream& os,A
//{
// os<
//}
//
//
//
//int main()
//{
// //CFather
// //CSon
//
// //father.show();
// //son.show();
// //son.CFather
//
//
// A
// CFather> *p=new CSon,int>(a,99);
//
//
// system("pause");
// return 0;
//}