标签:
《C++沉思录》集中反映C++的关键思想和编程技术,讲述如何编程,讲述为什么要这么编程,讲述程序设计的原则和方法,讲述如何思考C++编程。
1、你的类需要一个构造函数吗?
2、你的数据成员都是私有的合理吗?
3、你的类需要一个无参的构造函数吗?
是否需要生成类对象的数组!
4、你的每一个构造函数都初始化所有的数据成员了吗?
虽然这种说法未必总是正确,但是要积极思考!
5、你的类需要析构函数吗?
6、你的类需要一个虚析构函数吗?
7、你的类需要一个拷贝构造函数吗?
8、你的类需要重载赋值运算符吗?
9、你的操作运算符能正确将对象赋给对象本身吗?
class String { public: String& operator=(const String&); private: char* data; }; String& String::operator=(const String& str) { if (&str != this && this->data != NULL) { //释放旧值 delete[] data; //重新分配 this->data = new char[strlen(str.data) + 1]; //复制新值 strcpy(this->data, str.data); } return *this; }
10、你的拷贝构造函数和赋值运算符的参数类型加上const了吗?
X::X(const X& x); X& X::operator=(const X& x);
复制、赋值都不会改变原对象,所以 const;使用引用,免去值传递时的拷贝开销。
11、你的类需要重载其他关系运算符(==、!=、<、>等)吗?
12、删除数组时你记住delete [ ]了吗?
13、如果函数有引用类型参数,它们应该是const引用吗?
14、适当地声明成员函数为const了吗?
const类型对象只能调用“声明为const的成员函数”,而不能调用“非const的成员函数”。
http://blog.csdn.net/songshimvp1/article/details/50975332
代理类的作用:允许在一个容器中储存类型不同但是相互关联的对象。它允许将整个派生层次压缩在一个对象类型中。代理类是句柄类中最简单的一种。
class Vehicle { public: virtual double weight() const = 0; virtual void start() = 0; }; class Aircraft :public Vehicle { }; class Helicopter :public Aircraft { };对于我们要创建的Vehicle对象数组:Vehicle parking_lot [100];(1)Vehicle是一个抽象类,不能实例化对象;(2)即使有vehicle对象,把一个派生类对象赋给某个数组元素,还是会把派生类对象转换成一个vehicle对象,裁减掉所有在Vechile类中没有的成员,最终得到的并不是继承自vehicle的对象集合,仍旧是vehicle对象的集合。
第一种解决方法:这样使用数组:Vehicle* paking_lot [100]——存储指针,而不是储存对象本身。
这种方法会带来指针异常和动态内存管理的负担。另外我们还必须实现就知道要给某数组元素赋什么派生类型(静态)。
第二种解决方法:
class Vehicle { public: virtual double weight() const = 0; virtual void start() = 0; virtual Vehicle* copy() const = 0; //虚复制————根据需要复制对象,在运行时绑定属性 virtual ~Vehicle() = 0; //虚析构 }; class Truck :public Vehicle { double weight() const { } void start() { } Vehicle* copy() const { return new Truck(*this); //使用vp->copy()会得到一个指针,该指针指向该对象的一个新建的副本。 } }; class VehicleSurrogate //定义Vehicle的代理类——行为和Vehicle相似 { public: VehicleSurrogate(); //用来创建代理对象数组 VehicleSurrogate(const Vehicle&); //用来创建派生类对象的代理 ~VehicleSurrogate(); VehicleSurrogate(const VehicleSurrogate&); VehicleSurrogate& operator=(const VehicleSurrogate&); //Vehicle的其他操作 double weight(); void start(); private: Vehicle* vP; //关联 }; VehicleSurrogate::VehicleSurrogate() :vP(0) { } VehicleSurrogate::VehicleSurrogate(const Vehicle& v) :vP(v.copy()) { } VehicleSurrogate::~VehicleSurrogate() { delete vP; } VehicleSurrogate::VehicleSurrogate(const VehicleSurrogate& v) :vP(v.vP ? v.vP->copy() : 0) //(1)注意对v.vP的非0检测;(2)虚调用v.vP->copy(); { } VehicleSurrogate& VehicleSurrogate::operator=(const VehicleSurrogate& v) { if (this != &v) { delete vP; vP = (v.vP ? v.vP->copy() : 0); //(1)注意对v.vP的非0检测;(2)虚调用v.vP->copy(); } return *this; } double VehicleSurrogate::weight() { if (vP == 0) { throw "empty VehicleSurrogate.Weight()"; } return vP->weight(); } void VehicleSurrogate::start() { if (vP == 0) { throw "empty VehicleSurrogate.start()"; } return vP->start(); }然后,我们这么使用数组:——通过在容器中使用代理对象,而不是对象本身!
int index = 0; VehicleSurrogate parking_lot[1000]; Truck vT; parking_lot[++index] = VehicleSurrogate(vT);
(1)句柄要解决的问题:
上述使用代理类,我们看见了需要复制代理对象,复制消耗会很大,或者是不能轻易被复制(文件)。句柄类就是为了解决:句柄类允许在保持代理的多态行为的同时,还可以避免进行不必要的复制!
(2)句柄的简单实现——引用计数型句柄
使用句柄的原因之一就是为了避免不必要的对象复制,也就是得允许多个句柄绑定到同一个对象上,也就需要知道有多少个句柄绑定在同一个对象上,以便确定应当在何时删除对象。——使用引用计数来实现
#include <iostream> #include <string> #include <vector> using namespace std; class Point { public: Point() :xVal(0), yVal(0) { } Point(int x,int y) :xVal(x), yVal(y) { } int getX() const { return xVal; } int getY() const { return yVal; } Point& x(int x) { xVal = x; return *this; } Point& y(int y) { yVal = y; return *this; } private: int xVal; int yVal; }; class UPoint //该类纯粹是为了在添加引用计数后不重写Point而设计 { friend class Handle; private: UPoint() :u(1) {} UPoint(int x, int y):p(x, y),u(1) { } UPoint(const Point& p0):p(p0),u(1) { } private: Point p; int u; //引用计数——不能把引用计数放在句柄类 }; class Handle { public: Handle(); Handle(int, int); Handle(const Point&); Handle(const Handle&); Handle& operator=(const Handle&); ~Handle(); int getX() const; Handle& x(int); int getY() const; Handle& y(int); private: UPoint* uP; //句柄类关联UPoint类 }; Handle::Handle() : uP(new UPoint) { } Handle::Handle(int x, int y) :uP(new UPoint(x, y)) { } Handle::Handle(const Point& p) : uP(new UPoint(p)) { } Handle::Handle(const Handle& h) : uP(h.uP) //拷贝构造,这样原先的句柄和其副本都指向同一个UPoint对象 { ++uP->u; //引用计数加1,避免了复制Point } Handle& Handle::operator=(const Handle& h) //赋值运算符,左侧的句柄在赋值后将指向另外一个对象 { //首先递增右侧句柄指向对象的引用计数 ++h.uP->u; //然后递减左侧句柄所指向对象的引用计数 if (--(this->uP->u) == 0) { delete uP; } //赋值 this->uP = h.uP; return *this; } Handle::~Handle() { if (--uP->u == 0) //递减引用计数,如果引用计数减为0,就删除Upoint对象 { delete uP; } } //以下“存数据成员”方式是“值语义”,也就是所改动的那个UPoint对象不影响其他的UPoint对象 //{ // Handle h1(1, 2); // Handle h2 = h1; // h2.x(3); // int n = h1.x(); //输出1 //} //这就需要保证所改动的那个UPoint对象不能同时被其他任何Handle所引用 Handle& Handle::x(int x0) { if (this->uP->u != 1) //?没理解?——写时复制,只有在绝对必要时才复制,避免不必要的复制 { --this->uP->u; this->uP = new UPoint(this->uP->p); } this->uP->p.x(x0); return *this; } Handle& Handle::y(int y0) { if (this->uP->u != 1) { --this->uP->u; this->uP = new UPoint(uP->p); } this->uP->p.y(y0); return *this; } //如果是希望赋值以后,改变一个就影响到另外一个, //{ // Handle h1(1, 2); // Handle h2 = h1; // h2.x(3); // int n = h1.x(); //输出3 //} //这就需要保证h1和h2绑定到同一个对象上 Handle& Handle::x(int x0) { uP->p.x(x0); return *this; } Handle& Handle::y(int y0) { uP->p.y(y0); return *this; } int Handle::getX() const { return uP->p.getX(); } int Handle::getY() const { return uP->p.getY(); }
(3)句柄——分离引用计数(成员)
#include <iostream> #include <string> #include <vector> using namespace std; class Point { public: Point() :xVal(0), yVal(0) { } Point(int x,int y) :xVal(x), yVal(y) { } int getX() const { return xVal; } int getY() const { return yVal; } Point& x(int x) { xVal = x; return *this; } Point& y(int y) { yVal = y; return *this; } private: int xVal; int yVal; }; class Handle { public: Handle(); Handle(int, int); Handle(const Point&); Handle(const Handle&); Handle& operator=(const Handle&); ~Handle(); private: Point* p; //句柄类关联Point类,而不是UPoint类,这样的话我们不仅可以将Handle绑定到一个Point,还可以绑定到继承自Point类的对象上 int* u; }; Handle::Handle() : u(new int(1)) , p(new Point) { } Handle::Handle(int x, int y) : u(new int(1)), p(new Point(x, y)) { } Handle::Handle(const Point& p) : u(new int(1)), p(new Point(p)) { } Handle::Handle(const Handle& h) : u(h.u) ,p(h.p) //拷贝构造,这样原先的句柄和其副本都指向同一个UPoint对象 { ++*u; //引用计数加1,避免了复制Point } Handle& Handle::operator=(const Handle& h) //赋值运算符,左侧的句柄在赋值后将指向另外一个对象 { //首先递增右侧句柄指向对象的引用计数 ++*h.u; //然后递减左侧句柄所指向对象的引用计数 if (--*u == 0) { delete u; delete p; } //赋值 this->p = h.p; this->u = h.u; return *this; } Handle::~Handle() { if (--*u == 0) //递减引用计数,如果引用计数减为0,就删除Upoint对象 { delete u; delete p; } }
(4)句柄——分离引用计数(抽象成一个单独的类)
UseCount类可以在不了解其使用者任何信息的情况下与之合为一体,可以把这个类当成句柄实现的一部分,与各种不同的数据结构协同工作。
#include <iostream> #include <string> #include <vector> using namespace std; class Point { public: Point() :xVal(0), yVal(0) { } Point(int x,int y) :xVal(x), yVal(y) { } int getX() const { return xVal; } int getY() const { return yVal; } Point& x(int x) { xVal = x; return *this; } Point& y(int y) { yVal = y; return *this; } private: int xVal; int yVal; }; class UseCount //对引用计数的抽象 { public: UseCount() :p(new int(1)) { } UseCount(const UseCount& u) : p(u.p) { ++*p; } ~UseCount() { if (--*p == 0) delete p; } bool only() //描述该UseCount对象是否是唯一指向它的计数器的对象 { return *p == 1; } bool reattach(const UseCount& u) { ++*u.p; if (--*p == 0) { delete p; p = u.p; return true; } p = u.p; return false; } bool makeOnly() { if (*p == 1) { return false; } --*p; p = new int(1); return true; } private: int *p; }; class Handle { public: Handle(); Handle(int, int); Handle(const Point&); Handle(const Handle&); Handle& operator=(const Handle&); ~Handle(); int getX() const; Handle& x(int); int getY() const; Handle& y(int); private: Point* p; //句柄类关联Point类,而不是UPoint类,这样的话我们不仅可以将Handle绑定到一个Point,还可以绑定到继承自Point类的对象上 UseCount u; }; Handle::Handle() : p(new Point) { } Handle::Handle(int x, int y) : p(new Point(x, y)) { } Handle::Handle(const Point& p) : p(new Point(p)) { } Handle::Handle(const Handle& h) : u(h.u) ,p(h.p) //拷贝构造,这样原先的句柄和其副本都指向同一个UPoint对象 { } Handle& Handle::operator=(const Handle& h) { if (u.reattach(h.u)) { delete p; } this->p = h.p; return *this; } Handle::~Handle() { if (u.only()) { delete p; } } Handle& Handle::x(int x0) { if (u.makeOnly()) { p = new Point(*p); } p->x(x0); return *this; } Handle& Handle::y(int y0) { if (u.makeOnly()) { p = new Point(*p); } p->y(y0); return *this; } int Handle::getX() const { return p->getX(); } int Handle::getY() const { return p->getY(); }
标签:
原文地址:http://blog.csdn.net/songshimvp1/article/details/51568206