重载运营商
类,基本上,定义新类型的C ++代码中使用。和类型在C ++不仅通过代码结构和分配方式进行交互。他们还通过运营商的方式进行交互。例如,采取基本类型如下操作: | |
这里,一个基本类型(不同的变量
int
)被施加在加法运算,然后赋值运算符。对于一个基本算术式,这样的操作的意思是一般明显和明确的,但它可能不适合某些类类型是这样。例如:
| |
这里,它并不明显什么加法运算的该结果
b
和
c
不。事实上,仅此代码会导致编译错误,因为类型
myclass
有增加没有定义的行为。然而,C ++允许重载大多数运营商,使他们的行为可以为几乎任何类型的,包括类来定义。这里是可以被重载的所有操作符的列表:
重载操作 |
---|
+ - * / = < > += -= *= /= << >> <<= >>= == != <= >= ++ -- % & ^ ! | ~ &= ^= |= && || %= [] () , ->* -> new delete new[] delete[] |
运营商借助重载
operator
他们的名字开始的:功能,这是常规的功能具有特殊名称
operator
的关键字后面的
运营商标志的过载。语法是:
type operator sign (parameters) { /*... body ...*/ }
例如, 笛卡尔向量是一组两个坐标:
x
和
y
。的两个加法运算
笛卡尔矢量被定义为在加入这两种
x
坐标一起,两个
y
坐标在一起。例如,添加的
笛卡尔矢量
(3,1)
和
(1,2)
一起将导致
(3+1,1+2) = (4,3)
。这可以用C ++实现用下面的代码:
| | 4,3 |
|
如果感到困惑的这么多出场
CVector
,考虑到其中一些引用类名(即类)
CVector
和其他一些与该名称功能(即,构造函数,它必须具有相同的名称作为类)。例如:
| |
功能
operator+
类的
CVector
重载加法运算符(
+
)为该类型。一旦声明,该功能可以使用隐式操作,或明确使用其功能的名字叫:
| |
两个表达式是等价的。
该操作符重载是可以有任何的行为只是普通的功能; 实际上存在着由该过载执行操作带有一个相对于操作者的数学或通常含义没有要求,但它强烈推荐。例如,重载一类
operator+
实际减去或重载
operator==
填充对象用零,是完全有效的,尽管使用这样的类可以是具有挑战性的。
预期一个成员函数过载如操作参数
operator+
是自然的操作数的操作者的右手侧。这是共同的所有二进制运算符(那些带有一个操作数到它的左和一个操作数到它的右边)。但是,运营商可以进来形式多样。这里有一个表,需要为每个不同的运营商带来了可以被重载的参数的摘要(请更换
@
由每种情况下的运营商):
表达 | 操作者 | 成员函数 | 非成员函数 |
---|---|---|---|
@a | + - * & ! ~ ++ -- | A::operator@() | operator@(A) |
a@ | ++ -- | A::operator@(int) | operator@(A,int) |
a@b | + - * / % ^ & | < > == != <= >= << >> && || , | A::operator@(B) | operator@(A,B) |
a@b | = += -= *= /= %= ^= &= |= <<= >>= [] | A::operator@(B) | - |
a(b,c...) | () | A::operator()(B,C...) | - |
a->b | -> | A::operator->() | - |
(TYPE) a | TYPE | A::operator TYPE() | - |
a
是类的一个对象
A
,
b
是类的一个对象
B
,并
c
是类的对象
C
。
TYPE
只是任何类型(即运营商重载转换输入
TYPE
)。
请注意,一些运营商可能以两种形式被重载:无论是作为一个部件的功能或作为非成员函数:第一种情况已经在上面的例子中已经使用
operator+
。但一些运营商也可以被重载的非成员函数; 在这种情况下,操作函数采用适当的类作为第一个参数的对象。
例如:
| | 4,3 |
|
关键字此
关键字this
表示的指针,其成员功能正在执行的对象。它是一个类的成员函数中用来指对象本身。
一个其用途可以检查是否传递给一个成员函数的参数是对象本身。例如:
| | 是的,&A是B |
|
它也经常用于
operator=
通过引用返回对象的成员函数。与这些示例如下
笛卡尔矢量见过的,它的
operator=
功能可能被定义为:
| |
实际上,这个功能是非常类似于编译器隐式生成用于此类的代码
operator=
。
静态成员
一个类可以包含静态成员,无论是数据或功能。一类的静态数据成员也被称为“类变量”,因为只有一个用于同一类的所有对象共同变量,共享相同的值:即,其值不从该一个目的不同类到另一个。
例如,它可用于一类中的一个变量,它可以包含与当前分配,如在下面的例子该类的对象的数目的计数器:
| | 6 7 |
|
事实上,静态成员具有相同的属性为非成员变量,但他们享受类范围。出于这个原因,为了避免这些被宣布数次,它们不能直接在类进行初始化,而是需要它之外的某处被初始化。如前面的例子中:
| |
因为它是同一类的所有对象共同的变量值,它可以被称作该类的任何对象或甚至直接通过类名的一个成员(当然这是仅适用于静态成员):
| |
这两个以上的呼叫是指同一个变量:静态变量
n
类中
Dummy
这个类的所有对象共享。
再次,这是一样的非成员变量,但是,需要象类的成员(或对象),以访问一个名称。
类也可以有静态成员函数。这些代表是相同的:一类是常见的该类的所有对象成员,正是作为非成员函数,但像类的成员被访问。因为他们像非成员函数,它们不能访问类的非静态成员(既不成员变量,也没有成员函数)。他们既可以使用关键字
this
。
const成员函数
当一个类的一个目的是限定为一个const
对象:
| |
从类之外的数据成员的访问限制为只读,仿佛所有的数据成员
const
为那些从类的外部访问它们。但请注意,该构造仍称并允许初始化和修改这些数据成员:
| | 10 |
|
一个的成员函数
const
的对象可以当它们本身指定为只能被称为
const
成员; 在上面的例子中,构件
get
(其没有被指定为
const
)不能从调用
foo
。要指定一个成员是一个
const
成员,
const
关键字应遵循的函数原型,它的参数右括号后:
| |
注意,
const
可以用于限定由成员函数的返回类型。这
const
是不一样的其中之一指定的成员如
const
。两者都是独立的,位于在函数原型不同的地方:
| |
指定为成员函数
const
不能修改非静态数据成员,也呼吁其他非
const
成员函数。在本质上,
const
成员不得修改对象的状态。
const
对象不限于访问标记为唯一的成员函数
const
,但非
const
对象没有限制,并且因此能够访问
const
和非
const
成员函数一样。
你可能会认为,反正你很少去申报
const
对象,因而标记为const是不值得的努力,但const对象其实很普遍,不修改对象的所有成员。大多数功能服用类作为参数实际上把它们通过
const
参考,因此,这些功能只能访问他们的
const
成员:
| | 10 |
|
如果在本实施例中,
get
没有被指定为一个
const
部件,该呼叫到
arg.get()
在
print
功能将是不可能的,因为
const
对象只能访问
const
成员函数。
成员函数可以在其常量性超载:即,一类可具有除了一个相同的签名两个成员函数是
const
和另一种是不:在此情况下,
const
版本称为仅当对象是本身常量,并且非-
const
当对象是本身非版本称为
const
。
| | 15 20 |
|
类模板
就像我们可以创建功能模板,我们还可以创建类模板,允许类具有使用模板参数作为类型的成员。例如: | |
我们刚才定义的类用来存储任何有效类型的两个元素。例如,如果我们想声明这个类的一个对象来存储类型的两个整数值
int
与我们这样写值115和36:
| |
这个相同的类也可以用来创建一个对象来存储任何其它类型的,如:
| |
构造函数是在前面的类模板的唯一成员函数,它已被类定义本身内嵌定义。在一个成员函数类模板的确定指标外定义的情况下,应当先用
template <...>
前缀:
| | 100 |
|
注意成员函数的定义的语法
getmax
:
| |
这么多困惑
T
的?有三个
T
的本宣言:第一个是模板参数。第二种
T
是指由函数的返回类型。而第三
T
(尖括号之间的)也是有要求的:它指定了该功能的模板参数也是类模板参数。
模板特
有可能当特定类型作为模板参数传递来定义不同的实现的模板。这就是所谓的 模板特殊化。例如,假设我们有一个叫做非常简单的类
mycontainer
可以存储任何类型的一个元素,且只有一个叫做成员函数
increase
,这增加了它的价值。但是,我们发现,当它存储类型的元素
char
将是有一个完全不同的执行情况,函数成员更方便
uppercase
,所以我们决定宣布该类型的类模板特殊化:
| | 8 Ĵ |
|
这是用于类模板专门的语法:
| |
首先,注意到我们与前面的类名
template<>
,包括空参数列表。这是因为所有类型是已知的并没有模板参数都需要这种专业化,不过,它是一类模板的专业化,因此它需要要注意这样。
但是,除了这个前缀更重要的,是
<char>
类模板名称后面专业化参数。这种专业化参数本身标识该模板类被专业类型(
char
)。注意泛型类模板和专业化之间的区别:
| |
第一行是通用模板,而第二个是专业化。
当我们为一个模板类声明专业,我们还必须定义它的所有成员,即使是那些相同的通用模板类,因为没有从通用模板向专业化成员的“继承”。