components;
};
NewsLetter::NewsLetter(const NewsLetter& rhs)
{
// 遍历整个rhs链表,使用每个元素的虚拟拷贝构造函数
// 把元素拷贝进这个对象的component链表。
for (list::const_iterator it =
rhs.components.begin();
it != rhs.components.end();
++it) {
// \"it\" 指向rhs.components的当前元素,调用元素的clone函数,
// 得到该元素的一个拷贝,并把该拷贝放到
// 这个对象的component链表的尾端。
components.push_back((*it)->clone());
}
}
遍历被拷贝的NewsLetter对象中的整个component链表,调用链表内每个元素对象的虚拟构造函数。我们在这里需要一个虚拟构造函数,因为链表中包含指向NLComponent对象的指针,但是我们知道其实每一个指针不是指向TextBlock对象就是指向Graphic对象。无论它指向谁,我们都想进行正确的拷贝操作,虚拟构造函数能够为我们做到这点。
虚拟化非成员函数
就象构造函数不能真的成为虚拟函数一样,非成员函数也不能成为真正的虚拟函数。然而,既然一个函数能够构造出不同类型的新对象是可以理解的,那么同样也存在这样的非成员函数,可以根据参数的不同动态类型而其行为特性也不同。例如,假设你想为TextBlock和Graphic对象实现一个输出操作符。显而易见的方法是虚拟化这个输出操作符。但是输出操作符是operator<
(这样做也可以,不过看一看会发生什么:
class NLComponent {
public:
// 对输出操作符的不寻常的声明
virtual ostream& operator<
...
};
class TextBlock: public NLComponent {
public:
// 虚拟输出操作符(同样不寻常)
virtual ostream& operator<
};
class Graphic: public NLComponent {
public:
// 虚拟输出操作符 (不寻常)
virtual ostream& operator<
};
TextBlock t;
Graphic g;
...
t << cout; // 通过virtual operator<<
//把t打印到cout中。
// 不寻常的语法
g << cout; //通过virtual operator<<
印到cout中。
//不寻常的语法
类的使用者得把stream对象放到<
另一种方法是为打印操作声明一个虚拟函数(例如print)把它定义在TextBlock 和 Graphic类里。但是如果这样,打印TextBlock 和 Graphic对象的语法就与使用operator<
class NLComponent {
public:
virtual ostream& print(ostream& s) const = 0;
...
};
class TextBlock: public NLComponent {
public:
virtual ostream& print(ostream& s) const;
...
};
class Graphic: public NLComponent {
public:
virtual ostream& print(ostream& s) const;
...
};
inline
ostream& operator<
{
return c.print(s);
}
具有虚拟行为的非成员函数很简单。编写一个虚拟函数来完成工作,然后再写一个非虚拟函数,它什么也不做只是调用这个虚拟函数。为了避免这个句法花招引起函数调用开销,当然可以内联这个非虚拟函数。
现在你知道如何根据它们的一个参数让非成员函数虚拟化,你可能想知道是否可能让它们根据一个以上的参数虚拟化呢?可以,但是不是很容易。 来源:-计算机二级考试