我认为“值”与“对象”的区分在设计和实现时具有非常重要的指导作用,
因此下面做一些说明。
“值”与“对象”类型之间并没有严格定义的区分。但通常可以观察到下列不同:
0. “值”是“死的”、“傻的”、“简单的”、“具体的”、“可复制的”,
“对象”是“活的”、“聪明的”、“复杂的”、“抽象的”、“不可复制的”。
这里的“复杂性”主要还是指行为的复杂性,而非结构的复杂性。例如,
list< map< vector<string>, deque< set<int> > > >
仍然是一个不折不扣的“值”类型。
这里我们不在哲学的路上走太远,还是看看下面更具体的一些特征吧。
1. “值”的成员函数(包括解构函数)都不是 virtual 的,不是设计来被继承的。
“对象”的解构函数是 virtual 的,而且通常还有其它的 virtual 成员函数,
是设计来被继承的,或继承了其他基类。
// value:
struct String {
// non-virtual destructor:
~String() { delete[] s_; }
private:
char* s_;
};
// string should not be public-ly inherited.
// object:
struct OutputDevice {
virtual ~OutputDevice();
virtual void output( char const* ) = 0;
};
struct ConsoleOutputDevice : OutputDevice {
// inherits virtual destructor,
// overrides virtual member function:
void output( char const* );
};
2. “对象”经常必须通过指针或引用来使用,“值”不一定需要。
::std::auto_ptr<OutputDevice> output( new ConsoleOutputDevice() );
void f( OutputDevice& dev )
{
// ...
dev.output( "blah blah/n" );
// ...
}
String s = "dsjflsdjflsjlf";
String t = "djslfdsjfsl";
s += t;
void g( String s ) // by-value is OK.
{
// ...
}
g( s );
3. “值”可以复制出任意多份等价物,是 Assignable, CopyConstructible 的
(C++标准里定义了Assignable, CopyConstructible 的具体含义)。
“对象”通常不是 Assignable 也不是 CopyConstructible 的,通常是被共享的
不是被复制的。 即使“对象”被“克隆”,“克隆”出来的对象与原对象也不是
完全等价的:相同的基因,不同的个体。
string s = "dsjlfsdjlfsdjlfsdjl";
string t;
t = s;
// the following two lines are equivalent:
cout << s;
cout << t;
auto_ptr<OutputDevice> dev1( new ConsoleOutputDevice(...) );
auto_ptr<OutputDevice> dev2( dev1.clone() );
// the following two lines are NOT equivalent:
dev1->output( "blah blah" );
dev2->output( "blah blah" );
这里,dev2 可能具有与 dev1 相同的位置、大小、权限等属性,但却是
完全不同的另一个窗口。
4. 对于“值”类型,应该严格保证 constness-correctness,对于“对象”类型,
通常不需要,甚至有些 'const' 是有害的。
// bad design of a value type:
struct Contact {
string address(); // non-const
};
void f( Contact const& contact )
{
cout << contact.address(); // won't compile.
}
// maybe bad design of an intelligent object type:
struct Robot {
string name( Object const& asker ) const // const!
{ return my_name; }
private:
string my_name;
};
由于 Robot 的智能,问他一次名字也可能要触发它内部状态的改变。
一般来说,我们不应该对一个复杂“对象”假设任何操作不改变其内部状态,
因此其界面上不应有 const 成员函数。 使用一个 const Robot
也是毫无意义的。如果你觉得 Robot 比较特殊,可以想想 const Database。
5. “值”是可以比较的,“对象”通常是不可比较的,要比较的话,
应该比较对象的地址,而不是内容。
根据“值”类型表达的概念的特点,比较关系运算可分为两个层次:
a 相等性比较:
bool operator == ( T const& ) const;
bool operator != ( T const& ) const
{ return ! operator == ( other ); }
而且 operator !=( other ) 必须等价于 ! operator == ( other ),
operator == () 必须是一个“等价关系”(equivalence relationship):
任给 T a, b, c:
(自反的) (a == a) => true.
(对称的) (a == b) => (b == a).
(传递的) (a == b && b == c) => (a == c).
对于一个类型 T 的两个对象 a, b,如果表达式 (a == b) 可以转换为
bool 类型,而且这个 operator == () 是 T 上的一个等价关系,那么
就说 T 是 EqualityComparable 的。
b 排序关系比较:
bool operator < ( T const& ) const;
bool operator > ( T const& other ) const
{ return other < *this; }
bool operator >= ( T const& other ) const
{ return ! operator < ( other ); }
bool operator <= ( T const& other ) const
{ return ! operator > ( other ); }
这些运算之间的关系必须满足上面给出的实现所表达的等价性。
(因此通常只实现 operator<(),然后从这里 copy 另外三个!)
operator <() 必须是 T 上的一个“严格弱序”
(strict weak ordering)关系:
任给 T a, b, c:
(irreflexive) (a < a) => false.
(transitive) (a < b && b < c) => (a < c).
(weak ordering)
定义 eqiv(a,b) = ! (a < b) && ! (b < a).
equiv(a,b) && equiv(b,c) => eqiv(a,c).
这样,operator<() 可以在 equiv 决定的 T 的等价类上定义一个全序
(total ordering).
对于一个类型 T 的两个对象 a, b,如果表达式 (a < b) 可以转换为
bool 类型,而且这个 operator < () 是 T 上的一个严格弱序关系,
那么就说 T 是 LessThanComparable 的。
一个“值”类型可以只实现相等性比较。如果同时实现了排序关系比较,
那么必须有 (a == b) iff (! (a < b) && ! (b < a))。
上述对关系运算的要求来自于 C++ 标准中对容器类中对象的要求。即使
你的类型的对象不被放到标准容器中,也应该满足上述要求,否则就可能
产生一些让他人吃惊的行为。
综上所述,在设计一个类时,如果思考一下这个类表达的是一个简单的“值”
还是一个复杂的“对象”,非常有助于决定类的界面以及用法的许多方面:
. 会不会被继承/有没有 virtual 函数?
. 是否允许拷贝和赋值?还是必须共享/克隆?
. 如何对待 constness-correctness?
. 是否应该实现比较运算?实现哪些?
等等等等。
(除了“值”和“对象”的区分外,还有一批C++中的类型可以归类为
表达了一个“概念”,但那是另一个话题)
"三月的外星人" <UFO@sina.com> 写入消息
news:a8g76p$cb14@svr.novel.com...
> 标准中一些具体的类是否都应当看作是“值”类,比如“map",list,vector等?
> 而一些抽象的类就可以看成是”对象“类?
标准的数据类型大致有以下几类:
“值”:
各种基本类型:int, double, ...。各种指针。complex<>。
各种容器: vector<>, list<>, multi/set<>, multi/map<>, deque<>,
bitset<>, basic_string<>, valarray<>... 以及它们的各种 iterator。
adaptors: stack<>, queue<>, priority_queue<>。
各种 functor: less, greater, equal_to, plus, minus, binder1st...。
locale 是把“对象”类型通过共享方式包装成“值”类型,以方便使用。
“对象”:
iostream相关类:basic_ios<>, basic_*stream<>, basic_*streambuf<>。
各种facet: ctype_base/ctype<>, codecvt_base/codecvt<>...。
type_info。
“值与对象的混合物”
异常类:exception,bad_exception, logic_error, range_error...。
可以象“值”一样复制,但又有继承层次,可以通过基类(exception)
引用或指针来使用。这种设计在应用程序里最好避免,因为很容易引起
object-slicing:
exception e = domain_error( "sqrt(NegativeNumber)" );
上面一行能编译,能运行,但没有做想让它做的事。
“概念实现”:(象“值”一样简单,但不是用来装一个“值”的)
iterator<>, input_iterator_tag, output_iterator_tag...,
unary_function<>, binary_function<>...。
“特征描述”
iterator_traits<>, char_traits<>, numeric_limits<>...。
“怪物”:
auto_ptr<>。
|
相关推荐
提出了一种基于目标识别与显著性检测的图像场景多对象分割方法。该方法的步骤包括:在图像训 练 集 上训练语义对象的检测器,用来检测输入图像中对象的位置,标定对象的包围盒;对输入的图像进行过分割处理,得到超...
提出一种结合词特征与语义特征的评价对象识别方法。针对商品评论语料,使用条件随机场进行评价对象识别,在词特征、依存句法特征的基础上引入语义特征,并将各特征进行组合,以充分利用上下文信息,提高评价对象的...
具备模仿人类判断能力的语义相关度在很多方面尤其是自然语言处理领域...通过与其他算法进行对比实验可看出该算法与专家值重合度要远高于其他算法,而且对于计算对象无词性、语法以及语言等方面的限制,优越性较为明显。
Segment Anything Model自动全局语义分割,包含彩色掩膜导出代码,包含二值化掩膜代码。 Segment Anything Model是一种端到端的深度学习模型,它以全局的方式对图像进行语义分割。这意味着它不仅可以识别和分割预...
汽车和道路的语义分割Lyft感知挑战 目标: 从模拟汽车内部的前置摄像头数据对对象(汽车和路面)进行逐像素细分。 结果: 我开始挑战时一无所知。 我确定我什至不会进入前100名竞争者,但我想:“这太糟糕了,我喜欢...
Universes简介 Universe的创建 创建维度对象 创建度量对象 使用值列表 在对象上施加限制 使用函数 使用层次结构 聚合感知 Universe的链接 Universe的安全性控制 Universe的管理 Universe的元数据交换
面向对象系统分析与设计课件及复习资料 为老师上课用课件和复习指导 内容包括: 1.3 uml概述 1.3.1 uml简史 1.3.2 uml概貌 1.3.3 uml的特点和用途 第2章 面向对象的软件开发过程 2.1 rational统一...
结合微博文本的特点,对微博文本进行预处理,利用句法分析构建包括名词、名词短语、微博话题在内的评价对象候选集,再分别利用SVM模型、加权模型实现多特征融合的筛选候选评价对象方法,所用特征包括语义角色信息、...
语义学语义科学集成本体(SIO)提供类型和关系的简单集成本体,以丰富地描述对象,过程及其属性。 看一下的简要,其和,以及的已发表。 可在上获得OWL2本体。SIO的子集已准备好用于模块导入。查看本体 使用该本体的...
C++11的一个最主要的特性就是可以移动...一般而言,一个左值表达式表示的是一个对象的身份,而右值表达式表示的是对象的值。(可以取地址的、有名字的就是左值;不能取地址的、没有名字的就是右值。)两者明显的区别就
例如边缘、纹理、RGB 值、HSV 值、位置、每个超像素的线像素数等,以使用支持向量机训练模型并在测试中对超像素进行语义标记设置标签,如天空、树、路、草、水、建筑、山脉和前景对象。 然后将结果与地面实况进行...
如果A是具有值语义的POD(参见我关于值语义的博客:http://www.cnblogs.com/ly8838/p/3929025.html ),测试显示A 的创建和读写与一般变量没有任何差别,当然性能也不会有差别。 也是说,A a[3]
以UCI机器学习数据库中的两组数据集为研究对象,实验结果表明,它的精确度与自适应免疫聚类算法相当,能够得到准确的簇的数目,并且它的收敛速度更快,这对于如今网络数据的高速变化来说,该方法显得更为重要。
针对以多个关键词形成的节点集合作为输人的语义路径包含查询问题,提出了PS-Tree结构,并将其应用到语义搜索引擎的索引结构上.PS-Tree借鉴了面向对象数据库中的集合值属性索引的方法,通过范围查询快速地遍历树形...
论文清单 基于检测 基于细分简单的介绍实例语义分割是一个与检测和语义分割密切相关的领域。 特别地,可以将其视为检测加前景遮罩。 但大多数情况下,它无法分割非对象像素,例如天空,陆地等(在语义分割下被视为...
值语义:有些语言采用的不是这种方式,它们把变量的值直接保存在变量的存储区里,这种方式被我们称为值语义,例如C语言,采用这种存储方式,每一个变量在内存中所占的空间就要根据变量实际的大小而定,无法固定下来...
10.4与多个设计员一起工作 .................................... 389 10.5链接 Universe ........................................... 390 10.6在一个 Universe 中包含另一个 Universe ................... 399 ...
在本文中,我们对这些算法进行了全面的概述,主要分为直接进行二值化的本机解决方案,以及使用使...然后,我们对不同的任务进行了评估和讨论,包括图像分类,对象检测和语义分割。最后,展望了未来研究可能面临的挑战。