📄 [22] inheritance abstract base classes (abcs), c++ faq lite.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
<!-- saved from url=(0042)http://www.sunistudio.com/cppfaq/abcs.html -->
<HTML><HEAD><TITLE>[22] Inheritance abstract base classes (ABCs), C++ FAQ Lite</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META http-equiv=Content-Language content=zh-cn>
<META content=abcs.html name=FILENAME>
<META content="[22] Inheritance abstract base classes (ABCs), C++ FAQ Lite"
name=ABSTRACT>
<META content=cline@parashift.com name=OWNER>
<META content="Marshall Cline, cline@parashift.com" name=AUTHOR>
<META content="MSHTML 6.00.2462.0" name=GENERATOR>
<META content=FrontPage.Editor.Document name=ProgId><LINK rev=made
href="mailto:cline@parashift.com"><LINK
href="[22] Inheritance abstract base classes (ABCs), C++ FAQ Lite.files/cpp-faq.css"
type=text/css rel=stylesheet></HEAD>
<BODY>
<H1><A name=top></A>[22] 继承 — 抽象基类(ABCs)<BR><SMALL><SMALL>(Part of <A
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A>, <A
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">Copyright ©
1991-2001</A>, <A href="http://www.parashift.com/" target=OutsideTheFAQ>Marshall
Cline</A>, <A
href="mailto:cline@parashift.com">cline@parashift.com</A>)</SMALL></SMALL></H1>
<P>简体中文版翻译:<A href="http://www.sunistudio.com/nicrosoft">申旻</A>,<A
href="mailto:nicrosoft@sunistudio.com">nicrosoft@sunistudio.com</A>(<A
href="http://www.sunistudio.com/">东日制作室</A>,<A
href="http://www.sunistudio.com/asp/sunidoc.asp">东日文档</A>)</P>
<HR>
<H3>FAQs in section [22]:</H3>
<UL>
<LI><A href="http://www.sunistudio.com/cppfaq/abcs.html#[22.1]">[22.1]
将接口和实现分离的作用是什么?</A>
<LI><A href="http://www.sunistudio.com/cppfaq/abcs.html#[22.2]">[22.2]
在C++中如何分离接口和实现(就象 Modula-2)?</A>
<LI><A href="http://www.sunistudio.com/cppfaq/abcs.html#[22.3]">[22.3]
什么是 ABC?</A> <IMG alt=UPDATED!
src="[22] Inheritance abstract base classes (ABCs), C++ FAQ Lite.files/updated.gif">
<LI><A href="http://www.sunistudio.com/cppfaq/abcs.html#[22.4]">[22.4]
什么是“纯虚”成员函数?</A> <IMG alt=UPDATED!
src="[22] Inheritance abstract base classes (ABCs), C++ FAQ Lite.files/updated.gif">
<LI><A href="http://www.sunistudio.com/cppfaq/abcs.html#[22.5]">[22.5]
如何为包含指向(抽象)基类的指针的类定义拷贝构造函数或赋值操作符?<BR></A></LI></UL>
<HR>
<P><A name=[22.1]></A>
<DIV class=FaqTitle>
<H3>[22.1] 将接口和实现分离的作用是什么?</H3></DIV>
<P>接口是公司最有价值的资源。设计接口比用一堆类来实现这个接口更费时间。而且接口需要更昂贵的人力的时间。<BR><BR>既然接口如此有价值,它们应该被保护,以免因为数据结构和其他实现的改变而被破坏。因此,应该将接口和实现分离。
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/abcs.html#top">Top</A> | <A
href="http://www.sunistudio.com/cppfaq/abcs.html#bottom">Bottom</A> | <A
href="http://www.sunistudio.com/cppfaq/proper-inheritance.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=[22.2]></A>
<DIV class=FaqTitle>
<H3>[22.2] 在C++中如何分离接口和实现(就象 Modula-2)?</H3></DIV>
<P>使用<A
href="http://www.sunistudio.com/cppfaq/abcs.html#[22.3]">ABC</A>。(译注:即抽象基类 abstract base class)
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/abcs.html#top">Top</A> | <A
href="http://www.sunistudio.com/cppfaq/abcs.html#bottom">Bottom</A> | <A
href="http://www.sunistudio.com/cppfaq/proper-inheritance.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=[22.3]></A>
<DIV class=FaqTitle>
<H3>[22.3] 什么是 ABC? <IMG alt=UPDATED!
src="[22] Inheritance abstract base classes (ABCs), C++ FAQ Lite.files/updated.gif"></H3></DIV><SMALL><EM>[Recently
renamed "subclass" to "derived class" (on 7/00). <A
href="http://www.sunistudio.com/cppfaq/abcs.html#[22.4]">Click here to go to the
next FAQ in the "chain" of recent
changes<!--rawtext:[22.4]:rawtext--></A>.]</EM></SMALL>
<P>抽象基类(abstract base class)。
<P>在设计层次,抽象基类(ABC)对应于抽象概念。如果你问一个机修工他是否修理交通工具,他可能想知道你所说的是哪种交通工具。他不修理航天飞机、远洋轮、自行车或核潜艇。问题在于“交通工具”是一个抽象概念(例如,除非你知道你要建造哪种交通工具,否则你无法建造一个“交通工具”)。在C++中,<TT>Vehicle</TT>(交通工具)类是一个ABC,而<TT>Bicycle</TT>(自行车),<TT>SpaceShuttle</TT>(航天飞机)等则是派生类(<TT>OceanLiner(远洋轮)</TT>是一种<TT>Vehicle</TT>)。在真实世界的OO中,ABC无处不在。<BR><BR>在程序语言层次上,抽象基类(ABC)是有一个或多个<A
href="http://www.sunistudio.com/cppfaq/abcs.html#[22.4]">纯虚</A>成员函数的类。无法建立抽象基类的对象(实例)。
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/abcs.html#top">Top</A> | <A
href="http://www.sunistudio.com/cppfaq/abcs.html#bottom">Bottom</A> | <A
href="http://www.sunistudio.com/cppfaq/proper-inheritance.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=[22.4]></A>
<DIV class=FaqTitle>
<H3>[22.4] 什么是“纯虚”成员函数? <IMG alt=UPDATED!
src="[22] Inheritance abstract base classes (ABCs), C++ FAQ Lite.files/updated.gif"></H3></DIV><SMALL><EM>[Recently
renamed "subclass" to "derived class" (on 7/00). <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.1]">Click
here to go to the next FAQ in the "chain" of recent changes<!--rawtext:[23.1]:rawtext--></A>.]</EM></SMALL>
<P>将普通类变成抽象基类(也就是ABC)的成员函数。通常只在派生类中实现它。
<P>某些成员函数只在概念中存在,而没有合理的定义。例如,假设我让你在坐标<TT>(x,y)</TT>处画一个图形,大小为 7。你会问我:“我应该画哪种图形?”(圆,矩形,六边形等,画法都不同)。在C++中,我们必须指出 <TT>draw()</TT> 成员函数的实在物(由此用户才能在有一个<TT>Shape*</TT>或者 <TT>Shape&</TT> 的时候调用它),但我们认识到,在逻辑上,它只能在子类中被定义:
<P>
<DIV
class=CodeBlock><TT> class Shape {<BR> public:<BR> virtual void draw() const = 0; </TT><EM>// = 0 表示它是 "纯虚" 的</EM><TT><BR> </TT><EM>// ...</EM><TT><BR> };
</TT></DIV>
<P>这个纯虚函数使 <TT>Shape</TT> 成为了ABC(抽象基类)。如果你愿意,你可以将“<TT>= 0;</TT>”语法看作为代码位于NULL指针处。因此 <TT>Shape</TT> 向它的用户承诺了一个服务,然而 <TT>Shape</TT> 无法提供任何代码来实现这个承诺。这样做使得即使基类没有足够的信息来实际定义成员函数时,也强制了任何由 <TT>Shape</TT> 派生的具体类的对象须给出成员函数。
<P>注意,为纯虚函数提供一个实现是可能的,但是这样通常会使初学者糊涂,并且最好避免这样,直到熟练之后。
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/abcs.html#top">Top</A> | <A
href="http://www.sunistudio.com/cppfaq/abcs.html#bottom">Bottom</A> | <A
href="http://www.sunistudio.com/cppfaq/proper-inheritance.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=[22.5]></A>
<DIV class=FaqTitle>
<H3>[22.5] 如何为包含指向(抽象)基类的指针的类定义拷贝构造函数或赋值操作符?</H3></DIV>
<P>如果类拥有被(抽象)基类指针指向的对象,则在(抽象)基类中使用<A
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#[20.5]">虚构造函数用法</A>。就如同一般用法一样,在基类中声明一个<A
href="http://www.sunistudio.com/cppfaq/abcs.html#[22.4]">纯虚</A>方法 <TT>clone()</TT> :
<P>
<DIV
class=CodeBlock><TT> class Shape {<BR> public:<BR> </TT><EM>// ...</EM><TT><BR> virtual Shape* clone() const = 0; </TT><EM>// <A
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#[20.5]">虚拟(拷贝)构造函数</A></EM><TT><BR> </TT><EM>// ...</EM><TT><BR> };
</TT></DIV>
<P>然后在每个派生类中实现 <TT>clone()</TT>方法:
<P>
<DIV
class=CodeBlock><TT> class Circle : public Shape {<BR> public:<BR> </TT><EM>// ...</EM><TT><BR> virtual Shape* clone() const { return new Circle(*this); }<BR> </TT><EM>// ...</EM><TT><BR> };<BR> <BR> class Square : public Shape {<BR> public:<BR> </TT><EM>// ...</EM><TT><BR> virtual Shape* clone() const { return new Square(*this); }<BR> </TT><EM>// ...</EM><TT><BR> };
</TT></DIV>
<P>现在假设每个 <TT>Fred</TT>
对象有一个 <TT>Shape</TT>对象。<TT>Fred</TT>对象自然不知道 <TT>Shape</TT>是圆还是矩形还是……。<TT>Fred</TT>的拷贝构造函数和赋值操作符将调用<TT>Shape</TT>的<TT>clone()</TT>方法来拷贝对象:
<P>
<DIV
class=CodeBlock><TT> class Fred {<BR> public:<BR> Fred(Shape* p) : p_(p) { assert(p != NULL); } </TT><EM>// <TT>p</TT> must not be <TT>NULL</TT></EM><TT><BR> ~Fred() { delete p_; }<BR> Fred(const Fred& f) : p_(f.p_->clone()) { }<BR> Fred& operator= (const Fred& f)<BR> {<BR> if (this != &f) { </TT><EM>// 检查自赋值</EM><TT><BR> Shape* p2 = f.p_->clone(); </TT><EM>// Create the new one FIRST...</EM><TT><BR> delete p_; </TT><EM>// ...THEN <TT>delete</TT> the old one</EM><TT><BR> p_ = p2;<BR> }<BR> return *this;<BR> }<BR> </TT><EM>// ...</EM><TT><BR> private:<BR> Shape* p_;<BR> };
</TT></DIV>
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/abcs.html#top">Top</A> | <A
href="http://www.sunistudio.com/cppfaq/abcs.html#bottom">Bottom</A> | <A
href="http://www.sunistudio.com/cppfaq/proper-inheritance.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=bottom></A><A href="mailto:cline@parashift.com"><IMG height=26
alt=E-Mail
src="[22] Inheritance abstract base classes (ABCs), C++ FAQ Lite.files/mbox.gif"
width=89> E-mail the author</A><BR>[ <A
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A>
| <A
href="http://www.sunistudio.com/cppfaq/index.html#table-of-contents">Table of contents</A>
| <A
href="http://www.sunistudio.com/cppfaq/subject-index.html">Subject index</A>
| <A
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.1]">About the author</A>
| <A
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">©</A>
| <A
href="http://www.sunistudio.com/cppfaq/on-line-availability.html#[2.2]">Download your own copy</A> ]<BR><SMALL>Revised
Apr 8, 2001</SMALL> </P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -