C++ Primer中级(续)
14.转换操作符
转换函数
operator int() const;
注意:
1.必须是成员函数
2.不能指定返回类型
3.形参表必须是空的
4.必须显式地返回一个指定类型的值
5.不应该改变被转换对象,通常定义为const
#include <iostream> #include <string> using namespace std; class Dog { public: Dog(string n,int a,double w):name(n), age(a),weight(w) { } operator int() const { return age; } private: int age; double weight; string name; }; int main() { int a,b; a=10; b=a; Dog d("Bill",6,15.0); b = d; cout<<b<<endl; return 0; }
15.定义基类和派生类
基类
virtual函数
protected成员
派生类
类派生列表
重定义virtual函数
可以访问基类的public和protected成员
16.动态绑定
多态性
从派生类到基类的转换
引用或指针既可以指向基类对象,也可以指向派生类对象
只有通过引用或指针调用虚函数才会发生动态绑定
#include <iostream> #include <string> using namespace std; class Animal { }; class Dog:public Animal { }; class Cat:public Animal { }; class Item_base { public: int x; Item_base(const string &book="",double sales_price=0.0): isbn(book),price(sales_price){} string book() const { return isbn; } virtual double net_price(size_t n) const { return n*price; }//虚函数可以在继承以后重新定义 private: string isbn; protected: double price; }; class Bulk_item:public Item_base { public: Bulk_item(const string &book="",double sales_price=0.0, size_t qty=0,double disc_rate=0.0):Item_base(book,sales_price), min_qty(qty),discount(disc_rate) { } void test() { cout<<x<<endl; cout<<price<<endl; //cout<<isbn<<endl; } void test2(const Bulk_item&d ,const Item_base&b) { cout<<d.price<<endl; //cout<<b.price<<endl; } double net_price(size_t cnt) const { if(cnt>=min_qty) return cnt*(1-discount)*price; else return cnt*price; } private: size_t min_qty; double discount; }; void print_total(ostream& os,Item_base* item,size_t n) { os<<"ISBN:"<<item->book()<<"\t number: "<<n<<"\t total price: "<<item->net_price(n)<<endl; } int main() { Item_base* a = new Item_base("1-234-567-01",11.0); Bulk_item* b = new Bulk_item("1-234-567-02",22.0,2,0.05); //Bulk_item* c = new Item_base("1-234-567-01",11.0); print_total(cout,a,2); print_total(cout,b,3); //print_total(cout,c,2); Item_base* books[5]; books[0] = new Item_base("0-123-456-01",10.0); books[1] = new Bulk_item("0-123-456-02",20.0,6,0.05); books[2] = new Item_base("0-123-456-03",30.0); books[3] = new Bulk_item("0-123-456-04",40.0,4,0.15); books[4] = new Bulk_item("0-123-456-05",50.0,2,0.18); int num[5]; num[0] = 2; num[1] = 10; num[2] = 1; num[3] = 5; num[4] = 3; for(int i=0;i<5;++i) { print_total(cout,books[i],num[i]); } return 0; }
17.三种继承
公有、私有、受保护继承
接口继承和实现继承
修改继承访问(去除个别成员)
默认继承访问级别
#include <iostream> #include <string> #include <vector> using namespace std; class A { public: int a; A() { a=10; b=20; c=30; } void test() { cout<<c<<endl; } protected: int b; private: int c; }; class B1:public A { public: void test() { cout<<a<<endl; cout<<b<<endl; //cout<<c<<endl; } }; class C:public B1 { public: void test() { cout<<a<<endl; cout<<b<<endl; //cout<<c<<endl; } }; class B2:private A { public: using A::a; void test() { cout<<a<<endl; cout<<b<<endl; } }; class B4:A//默认是private { }; int main() { B1 b1; cout<<b1.a<<endl; //cout<<b1.b<<endl; b1.test(); //cout<<b1.b<<endl; //cout<<b1.c<<endl; B2 b2; cout<<b2.a<<endl; return 0; }
18.派生类的构造函数和析构函数
派生类的构造函数
执行基类的构造函数
执行成员对象的构造函数
执行派生类的构造函数
派生类的析构函数
对派生类新增普通成员进行清理
调用成员对象析构函数
调用基类析构函数
#include <iostream> #include <string> #include <vector> using namespace std; class Base1 { public: Base1(int i) { b1 = i; cout<<"Base1的构造函数"<<endl; } void Print() const { cout<<b1<<endl; } private: int b1; }; class Base2 { public: Base2(int i) { b2 = i; cout<<"Base2的构造函数"<<endl; } void Print() const { cout<<b2<<endl; } private: int b2; }; class Base3 { public: Base3() { b3 = 0; cout<<"Base3的缺省构造函数"<<endl; } void Print() const { cout<<b3<<endl; } private: int b3; }; class Member { public: Member(int i) { m=i; cout<<"Member的构造函数被调用"<<endl; } int GetM() { return m; } private: int m; }; class Derived:public Base1,public Base2,public Base3 { public: Derived(int i,int j,int k,int l); void Print(); private: int d; Member mem; }; Derived::Derived(int i,int j,int k,int l):Base1(i),Base2(j),mem(k) { d=l; cout<<"派生类的构造函数被调用"<<endl; } void Derived::Print() { Base1::Print(); Base2::Print(); Base3::Print(); cout<<mem.GetM()<<endl; cout<<d<<endl; } int main() { Derived obj(1,2,3,4); obj.Print(); return 0; }
19.转换与继承
派生类到基类
引用转换
指针转换
对象转换
基类到转换类
基类到派生类的自动转换不存在
强制转换
Bulk_item *p = static_cast<Bulk_item *>(&item)
20.友元与继承
友元可以访问类的private和protected成员
友元关系不能继承
#include <iostream> #include <string> #include <vector> using namespace std; class Base //你爸爸 { friend class Frnd; friend class D2; protected: int i; }; class D1:public Base//你 { friend class Frnd; friend class D2; protected: int j; }; class Frnd//我爸爸 { public: int mem(Base b) {return b.i;} int mem(D1 d){return d.j;} }; class D2:public Frnd//我 { public: int mem(Base b){return b.i;} int mem(D1 d){return d.j;} }; int main() { Base a; D1 b; Frnd c; D2 d; return 0; }
21.静态成员与继承
基类中的static成员,在整个继承层次中只有一个实例
在派生类中访问static成员的方法
1.基类名::成员名
2.子类名::成员名
3.对象.成员名
4.指针->成员名
5.成员名
#include <iostream> #include <string> #include <vector> using namespace std; class A { public: static size_t object_count() { return 100; } protected: static const size_t obj_count=99; }; class B:public A { public: void f(const B &b,B *b2) { //b.obj_count = 101; //A::obj_count = 99; cout<<A::obj_count<<endl; cout<<B::obj_count<<endl; cout<<b.obj_count<<endl; cout<<obj_count<<endl; cout<<b2->obj_count<<endl; cout<<endl; cout<<A::object_count()<<endl; cout<<B::object_count()<<endl; cout<<b.object_count()<<endl; cout<<object_count()<<endl; cout<<b2->object_count()<<endl; } }; class C:public B { public: void f1() { cout<<object_count()<<endl; } }; int main() { B b; b.f(b,&b); C c; c.f(b,&b); return 0; }
22.纯虚函数与抽象类
纯虚函数
抽象类 - 抽象数据类型
任何包含一个或多个纯虚函数的类都是抽象类
不要创建这个类的对象,应该继承它
务必覆盖从这个类继承的纯虚函数
实现纯虚函数
C++接口
就是只包含纯虚函数的抽象基类
#include <iostream> #include <string> #include <vector> using namespace std; class Shape { public: Shape(){} virtual ~Shape(){} //virtual double GetArea() = 0; virtual double GetPerim() = 0; virtual void Draw() = 0; virtual void Speak(){cout<<"Test"<<endl;} }; class Circle:public Shape{ public: Circle(int radius):itsRadius(radius){} virtual ~Circle(){} double GetArea(){return 3.14*itsRadius*itsRadius;} double GetPerim(){return 2*3.14*itsRadius;} void Draw(); private: int itsRadius; }; void Circle::Draw() { cout<<"Circle drawing routine here!"<<endl; } class Rectangle:public Shape { public: Rectangle(int len,int width):itsLength(len),itsWidth(width){} virtual ~Rectangle(){} double GetArea(){return itsLength*itsWidth;} double GetPerim() {return 2*itsLength+2*itsWidth;} virtual int GetLength() {return itsLength;} virtual int GetWidth() {return itsWidth;} void Draw(); private: int itsWidth; int itsLength; }; void Rectangle::Draw() { for(int i=0;i<itsLength;++i) { for(int j=0;j<itsWidth;++j) cout<<"x "; cout<<endl; } } class Square :public Rectangle { }; int main() { Circle a(10); a.Draw(); Rectangle b(10,5); b.Draw(); b.Speak(); return 0; }
23.模板与泛型编程
两种模板
类模板、函数模板
泛型编程
主要用于容器、迭代器、算法 -> C++ STL 标准模板库
示例
1.普通队列
2.C++中的泛型队列
3.顺序队列
4.链式队列
24.函数模板
函数模板 -> 实例化 ->函数
模板形参
template <typename T>
template <class T>
四个例子
#include<iostream> #include <string> #include <fstream> #include <sstream> using namespace std; /* int compare(const double &v1,const double &v2) { if(v1<v2) return -1; if(v1>v2) return 1; if(v1==v2) return 0; } */ template<typename T> int compare(const T& v1,const T& v2) { if(v1<v2) return -1; if(v1>v2) return 1; if(v1==v2) return 0; } template<class T> T absVal(T val) { return val>0?val:-val; } template<typename T1,typename T2> T1& print(T1& s,T2 val) { s<<val; return s; } int main() { double d1=1.2,d2=2.2; cout<<compare(d1,d2)<<endl; string s1="hi",s2="hello"; cout<<compare(s1,s2)<<endl; double dval=-0.88; float fval = -12.3; string oristr = "this is a test"; string desstr; ostringstream oss(desstr); ofstream outFile("result.dat"); print(cout,-3)<<endl; print(cout,oristr)<<endl; print(outFile,-3)<<endl; outFile.close(); print(oss,-3)<<endl; cout<<absVal(dval)<<endl; cout<<absVal(fval)<<endl; return 0; }
24.智能指针、auto_ptr类
常规指针 - 容易产生内存泄漏
智能指针
使用std::auto_ptr智能指针
使用Boost智能指针
使用ATL框架中的智能指针如CComPtr、CComQIPtr等等
#include <iostream> #include <memory> using namespace std; void demo2() { auto_ptr<double> pd(new double); *pd = 28.5; cout<<*pd<<endl; } void demo1() { double d; d = 25.5; double *pd = new double; *pd = 25.5; cout<<d<<endl; cout<<*pd<<endl; delete pd; return; } int main() { demo1(); demo2(); return 0; }
25.命名空间
命名空间的定义
每个命名空间是一个作用域
命名空间可以是不连续的
接口和实现的分离
嵌套命名空间
命名空间成员的使用
using std::vector
using primer = cplusplus_primer
using namespace std;
26.多继承与虚基类
多继承
多继承中的二义性问题
虚基类(解决菱形继承)
虚基类的构造函数
#include <iostream> using namespace std; enum COLOR {Red,Green,Blue,Yellow,White,Black,Brown}; class Animal { public: Animal(int); virtual ~Animal() {cout<<"Animal系噶偶"<<endl;} virtual int GetAge() {return itsAge;} virtual void SetAge(int age){itsAge = age;} private: int itsAge; }; Animal::Animal(int age):itsAge(age) { cout<<"Animal构造函数"<<endl; } class Horse:virtual public Animal { public: Horse(COLOR color,int height,int age); virtual ~Horse(){cout<<"Horse析构函数被调用"<<endl;}; virtual void Whinny() const {cout<<"Whinny!..."<<endl;} virtual int GetHeight() const {return itsHeight;} virtual COLOR GetColor() const {return itsColor;} private: int itsHeight; COLOR itsColor; }; Horse::Horse(COLOR color,int height,int age):itsHeight(height),itsColor(color),Animal(age) { cout<<"Horse构造函数被调用"<<endl; } class Bird:virtual public Animal { public: Bird(COLOR color,bool migrates,int age); virtual ~Bird(){cout<<"Bird析构函数被调用"<<endl;} virtual void Chrip() const {cout<<"Chirp"<<endl;} virtual void Fly() const { cout<<"I can fly!"<<endl; } virtual bool GetMigration() const {return itsMigration;} virtual COLOR GetColor() const {return itsColor;} private: bool itsMigration; COLOR itsColor; }; Bird::Bird(COLOR color,bool migrates,int age):itsMigration(migrates),itsColor(color),Animal(age) { cout<<"Bird构造函数被调用"<<endl; } class Pegasus:public Horse,public Bird { public: Pegasus(COLOR,int,bool,long,int); ~Pegasus(){cout<<"Pegasus析构函数被调用"<<endl;} void Chrip() const { Whinny();} virtual long GetNumberBelievers() const { return itsNumberBelievers; } private: long itsNumberBelievers; }; Pegasus::Pegasus(COLOR aColor,int height,bool migrates,long numBelieve,int age): Horse(aColor,height,age), Bird(aColor,migrates,age), itsNumberBelievers(numBelieve), Animal(age) { cout<<"Pegasus构造函数被调用"<<endl; } int main() { Pegasus *pPeg = new Pegasus(Red,5,true,10,100); //char *p = new char [5]; //char *p1 = new char('s'); pPeg->Fly(); pPeg->Whinny(); pPeg->Chrip(); cout<<pPeg->Horse::GetColor()<<endl; cout<<pPeg->Bird::GetColor()<<endl; cout<<"有"<<pPeg->GetNumberBelievers()<<"相信"<<endl; cout<<pPeg->GetAge()<<endl; delete pPeg; return 0; }
27.特殊工具与技术
allocator类
RTTI
类成员的指针
嵌套类
union
局部类
位域
volatile
extern ”C“
#include <iostream> #include <string> using namespace std; class Item_base { public: virtual double net_price(size_t n) const { return n*price; } public: string isbn; protected: double price; }; class Bulk_item: public Item_base { public: double net_price(size_t cnt) const { if (cnt>min_qty) return cnt*(1-discount)*price; else return cnt*price; } private: size_t min_qty; double discount; }; union TokenValue { char cval; int ival; double dval; }; typedef unsigned int Bit; class File{ public: Bit mode: 2; Bit modified: 1; Bit prot_owner: 3; Bit prot_group: 3; Bit prot_world: 3; }; extern "C" void show(char *); int main() { show("hello extern \"C\"\n"); TokenValue myToken = {'a'}; cout<<myToken.ival<<endl; Item_base *pItem = new Item_base(); allocator<Item_base> a; a.allocate(100); Item_base *bp = new Item_base(); Bulk_item *dp = new Bulk_item(); Item_base *bp2 = dp; Bulk_item *dp2 = dynamic_cast<Bulk_item*> (bp);//动态类型转换 RRTI 运行时类型识别 if(typeid(Bulk_item) == typeid(*dp)) cout<<"Bulk_item类型"<<endl; cout<<typeid(*bp).name()<<endl; //类成员指针 string Item_base::* p = &Item_base::isbn; double (Item_base::*pmf)(size_t) const = &Item_base::net_price; return 0; }