码迷,mamicode.com
首页 > 编程语言 > 详细

C++对象模型——构造,解构,拷贝语意学(第五章)

时间:2015-08-12 19:25:32      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:

第5章 构造,解构,拷贝语意学 (Semantics of Construction, Destruction, and Copy)

    考虑下面这个abstract base class 声明:
class Abstract_base {
public:
	virtual ~Abstract_base() = 0;
	virtual void interface() const = 0;
	virtual const char * mumble() const { return _mumble; }
protected:
	char *_mumble;
};
有什么问题?虽然这个 class 被设计为一个抽象的base class(其中有pure virtual function,使得Abstract_base不可能拥有实体),但它仍然需要一个明确的构造函数以初始化其data member _mumble.如果没有这个初始化操作,其derived class 的局部性对象_mumble将无法决定初值,例如:
class Concrete_derived : public Abstract_base {
public:
	Concrete_derived();
};
void foo() {
	// Abstract_base::_mumble未被初始化
	Concrete_derived trouble;
}
可能说是:也许Abstract_base的设计者试图让其每一个derived class 提供_mumble的初值.然而如果这样,derived class 的唯一要求就是Abstract_base必须提供一个带有唯一参数的 protected constructor:
Abstract_base::Abstract_base(char *mumble_val = 0) : _mumble(mumble_value)
{}
一般而言,class 的data member应该初始化,并且只在constructor中或是在 class 的其他member functions中指定初值,其他任何操作都将破坏封装性质,使 class 的维护和修改更加困难.
    当然也可能是说设计者的错误并不在于未提供一个 explicit constructor,而是不应该在抽象的base class 中声明data member.这是比较强而有力的论点(把interface和implementation分离),但它并不是行遍天下皆有理,因为将"被共享的数据"抽取出来放在base class 中,毕竟是一种正当的设计.

纯虚拟函数的存在 (Presence of Pure Virtual Function)

    C++可以定义和调用(invoke)一个pure virtual function;不过它只能被静态地调用(invoke statically),不能经由虚拟机制调用.例如,可以合法写下这段代码:
// OK:定义pure virtual function,但只能被静态地调用(invoked statically)
inline void Abstract_base::interface() const {
	function
	// ...
}
inline void Concrete_derived::interface() const {
	// OK:静态调用(static invocation)
	Abstract_base::interface();
	function
	// ...
}
要不要这样做,全由 class 设计者决定.唯一的例外就是pure virtual destructor:class 设计者一定得定义它.为什么?因为每一个derived class destructor会被编译器加以扩展,以静态调用的方式调用其"每一个virtual base class"以及"上一层base class"的destructor.因此,只要缺乏任何一个base class desstructors的定义,就会导致链接失败.
    难道对一个pure virtual destructor的调用操作,不应该在"编译器扩展derived class的destructor"时压抑下来吗?不!class 设计者可能已经真的定义了一个pure virtual destructor(就像上一个例子中定义了Abstract_base::interface()那样).这样的设计是以C++语言的一个保证为前提:继承体系中每一个 class object的destructor都会被调用,所以编译器不能够压抑这个调用操作.
    一个比较好的替代方案就是,不要把 virtual destructor声明为pure.

虚拟规格的存在 (Presence of a Virtual Specification)

    如果决定把Abstract_base::mumble()设计为一个 virtual function,那将是一个糟糕的选择,因为其函数定义内容并不与类型有关,因而几乎不会被后继的derived class 改写.此外,由于它的non-virtual 函数实体是一个 inline 函数,如果常常被调用的话,效率上的负担实在不低.
    然而,编译器难道不能经由分析,知道该函数只有一个实体存在于 class 层次体系中?果真如此的话,难道它不能够把调用操作转换为一个静态调用操作(static invocation),以允许调用操作的 inline expansion?如果 class 层次体系陆续被加入新的 class,带有这个函数的新实体,又当如何?是的,新的 class 会破坏优化.该函数现在必须被重新编译(或是产生第二个--也就是多态--实体,编译器将通过流程分析哪一个实体要被调用).不过,函数可以以二进制形式存在与一个library中.
    一般而言,把所有的成员函数都声明为 virtual function,然后再靠编译器的优化操作把非必要的 virtual invocation去除,并不是好的设计观念.

虚拟规格中的 const 的存在

    决定一个 virtual function是否需要 const,似乎是件琐碎的事情.但当真的面对一个abstract base class 时,却不容易做决定.做这件事情,意味着得假设subclass实体可能被无穷次数地使用.不把函数声明为 const,意味着该函数能够获得一个 const reference或 const pointer.

重新考虑 class 的声明

    由前面的讨论可知,重新定义Abstract_base如下,才是比较适当的一种假设:
class Abstract_base {
public:
	virtual ~Abstract_base();						// 不再是pure
	virtual void interface() = 0;
	const char *mumble() const { return _mumble; }	// 不再是virtual
protected:
	Abstract_base(char *pc = 0);					// 新增一个带有唯一参数的constructor
	char *_mumble;
};

版权声明:本文为博主原创文章,未经博主允许不得转载。

C++对象模型——构造,解构,拷贝语意学(第五章)

标签:

原文地址:http://blog.csdn.net/yiranant/article/details/47448829

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!