effective C++之构造、析构、赋值运算(二)

2015-07-20 17:09:04 · 作者: · 浏览: 10
irtual函数

假如你有以下class继承层次

class Transaction

{

public:

Transaction();

virtual void LogTransaction() const =0;//因为类型不同日志记录也会不同

....

};

?

Transaction::Transaction(){

LogTransaction();

}

class BuyTransaction:public Transaction{

public:

virtual void LogTransaction()const;//交易日志Buy

}

class SellTransaction:public Transaction

{

?

public:

virtual void LogTransaction()const;//交易日志Sell

?

}

假如有以下语句 BuyTransaction那么LogTransaction此时调用的版本将是基类中的版本并不是BuyTransaction内的版本,base class 构造期间内的virtual 函数绝对不会下降到derived class阶层(在base class构造期间virtual函数不是virtual函数)

一种解决方法:在class Transaction 内将logTransaction函数改为non-virtual 函数然后要求derived class构造函数传递必要的信息给logTransaction构造函数

clss Transaction{

public:

explict Transaction(const std::string& loginfo);

void LogTransaction(const std::string& loginfo) const ;

};

Transaction::Transaction(const std::string& loginfo)

{

....

logTransaction(loginfo)

}

class BuyTransaction::public Transaction

{

public:

BuyTransaction(prameter):Transaction(CreateString(praneter)){...}

private:

string CreateString(parameters)

}

请记住:

@在构造函数和析构函数期间不能调用virtual函数因为这类调用从不下降至derived class

条款10:令operator=返回一个reference to *this

形如:Widget& operator=(const Widget&rhs)

{

return *this;

}

请记住:

令赋值操作符返回一个reference to *this;

条款11:在operator=中处理“自我赋值”

假如你建立一个class用来保存一个指针指向动态分配的位图(bitmap)

class Bitmap{...}

class Widget{

private: Bitmap* pb;

}

operator=的实现代码:

传统方法是加入证同测试达到自我赋值的检验目的

Widget& Widget::operator=(const Widget& rhs)

{

if(this==&rhs)

return *this;

delete pb;

pb=new BitMap(*rhs.pb);

return *this;

}

如果你很关心程序效率 ,可以再次把证同测试放到函数开头,不过你有大致知道自我赋值的频率到底有多大因为证同测试同样需要成本
同样我们可以通过“copy and swap”技术来替代手工排序代码解决自我赋值的问题
class Wiget{};
void swap(Widget& rhs)
{
.......
}
Wiget& Widget::operator=(const Widget& rhs)
{
Widget temp(rhs);
swap(temp);
return *this;
}
更高效的代码:(基于1:某class的 copy assigment操作符可以被声明为以by value方式接受参数2:以by value方式传递东西会造成一份复件)
Wiget& Widget::operator=(Widget rhs)
{

swap(rhs);
return *this;
}

请记住:
@确保对象自我赋值时operator=有良好的行为,其中技术包括比较“来源对象”和“目的对象”的地址、精心周到的语句顺序,以及 copy-and-swap
@确定任何对象操作一个以上的对象,而其中多个对象时同一个对象时,其行为仍然正确

条款12 赋值对象时勿忘赋值对象的每一个成分

class Date{};
class A{
public :
A(const A&);
A& operator(const A&a);
private:
string m_strname;
Date m_Date;
};
不使用编译器提供的构造函数不要忘记复制对像的每个成分
class B:public A
{
public:
B(const B& b);
B& operator=(const B& b);
int m_p;
};

B::B(const B&b):A(B),m_p(b.m_p)//调用A的构造函数
{
logcall("copying");
}
B& B::coperator=(const B& b)
{
logcall("copying assignment");
A::operator=(B);
m_p=b.m_p;
reutrn *this;
}
让 copy 构造函数调用 copy assignment操作符 和让copy assignment 操作符调用 copy构造函数两者都不会有意义!
若两个有相近的代码产生则通过引入第三个函数解决来降低代码重复
请记住:
@copying 函数应该确保赋值“对象的所有成员变量”有有base class 成分
@不要尝试以某个copying函数实现另一个copying函数,应该将共同的机能放进第三个函数中并由两个函数共同调用


?

?

?

?

?

??