unCopyable类
class unCopyable{
protected:
unCopyable(){}
~unCopyable(){}
private:
unCopyable(const unCopyable &);
unCopyable & operator=(const unCopyable&);
}
class home :private unCopyable{}
注意上面的基类的protected类型的构造函数和析构函数,子类是private继承。private继承是实现继承。
赋值操作符:
widget & widget::operator=(const widget& rh){
if(this == &rh)
return *this;
delete pb;
pb = new Bitmap(*rh.pb);
reruen *this;
}
这种函数虽然考虑了两者相同的情况,但是没有考虑当new操作发生异常时 的情况。当异常是,pb会指向已经释放的内存,导致不确定行为。
更好的方式是
widget & widget::operator=(const widget& rh){
Bitmap* porig = pb;
pb = new Bitmao(*rh.pb);
delete porig;
return *this;
}
这里即使两者相同,也不会有问题,只不过多做了一次拷贝,对效率有影响。我们可以考虑将判断语句加进去,但是判断语句会使代码变大,产生新的分支流,这两点都会降低CPU的效率。所以我们应该考虑自我赋值的发生频率有多高。
还有一个替代方案是copyandswap技术:
class widget{
private:
void swap(const widget&rh){}
public:
widget & widget::operator=(const widget& rh){
widget temp (rh);
swap(temp);
return *this;
}
C++定义隐式转换函数
C++中单参数构造函数若不声明为explict,在合适的场合可以产生隐式转换:由成员变量类型转换为类类型。
下面的代码展示如何实现反向的转换:
另外,两个或更多参数的non-explicit构造函数,如果所有形参都提供了默认实参,那么在需要一个类类型对象的表达式位置,提供一个first形参类型的对象,编译器也执行隐式转换,转换得到一个类对象。
如,构造函数Rational(int num1 = 0, int num2 = 1); Rational类中重载了operator*。表达式result = oneHalf * 2; 2发生隐式转换为Rational对象。result 和 onehalf为Rational对象。
隐式转换函数:
class Font{
private:
FontHandle f;
public :
operator FontHandle() const{//隐式转换
return f;
}
}
void changeFrontSize(FontHandle f ,int size){}
Font font;
int size;
当以Font对象调用changeFrontSize函数时,便会执行隐式转换函数,这样
changeFrontSize(font,size);
用对象管理资源的原因:
因为异常会导致函数未执行完提前返回,所以我们正常的在函数末尾释放资源会因为异常的发生造成内存泄露。所以要才有对象管理资源,当对象离开作用域时,会自动执行其析构函数,这样就会保证资源的释放。
ecplicit关键字
隐式转换可以用explict关键字防止。其主要是防止一个类型的对象转换出另一个新的类型的新对象。
默认构造函数是用于构造对象的,这两个没什么太大关系,将默认构造函数声明为explicit可以防止参数类型对象生成一个类类型的临时对象。
关于C++的shared_ptr,只有在其通过复制构造函数和赋值操作符时,两者的引用计数才和对象持有者相关。从以下两个例子可以看出来:
# include <iostream>
# include <tr1/memory>
using namespace std;
class A {
public:
A() {
cout << "construct A!!!" << endl;
}
;
~A() {
cout << "destruct A!!!" << endl;
}
;
};
class B: public A {
public:
B() {
cout << "construct B!!!" << endl;
}
;
~B() {
cout << "destruct B!!!" << endl;
}
;
};
int main() {
// B* ptrB0 = new B();
B * pint = new B();
std::tr1::shared_ptr<B> ptrB1(pint);
std::tr1::shared_ptr<B> ptrB2(ptrB1);
std::tr1::shared_ptr<B> ptrB3(ptrB1);
cout << ptrB1.use_count() << endl;
cout << ptrB2.use_count() << endl;
cout << ptrB3.use_count() << endl;
}
这个打印出的结果是3
# include <iostream>
# include <tr1/memory>
using namespace std;
class A {
public:
A() {
cout << "construct A!!!" << endl;
}
;
~A() {
cout << "destruct A!!!" << endl;
}
;
};
class B: public A {
public:
B() {
cout << "construct B!!!" << endl;
}
;
~B() {
cout << "destruct B!!!" << endl;
}
;
};
int main() {
// B* ptrB0 = new B();
B * pint = new B();
std::tr1::shared_ptr<B> ptrB1(pint);
std::tr1::shared_ptr<B> ptrB2(pint);
std::tr1::shared_ptr<B> ptrB3(pint);
cout << ptrB1.use_count() << endl;
cout << ptrB2.use_count() << endl;
cout << ptrB3.use_count() << endl;
}
这个的打印结果是1.
这也就说明引用计数和所对应的对象不是强相关的,自我理解应该是这样,当shared_ptr初始化时(通过非同类对象),会申请一块内存进行引用计数。当通过同类对象进行初始化时,就会使用同一块内存,而不是新申请。也就是只有通过赋值操作符和复制构造函数才会使引用计数有效。