<返回类型说明符>operator<运算符符号>(<参数列表>)
{
<函数体>
}
1.重载后的运算符不能改变运算符的优先级和结合性;2.重载是对原功能的适当改进故重载功能应当与原功能相近。
运算符函数重载一般有两种形式:重载为类的成员函数和重载为类的非成员函数(通常是友元)。
调用成员函数运算符的格式如下:
<>.operator<><()> <对象名><运算符><参数>,如a+b等价于a.operator+(b)。
调用友元函数运算符的格式如下(因为没有this指针所以形参会多一个):
operator<运算符>(<参数1>,<参数2>),等价于<参数1><运算符><参数2>,如a+b等价于operator+(a+b)。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1.构造函数的冒号后的初始化成员列表
2.类名冒号后的是用来定义类的继承
class 派生类名:继承方式 基类名
{
派生类的成员
};
继承方式有public,private,protected,默认是public
char zhou;
void sleep()
{
char zhou;
::char(局部变量)=::char(全局变量)*char(局部变量);
}
class 类名
{
定义一个点(Point)类, 具有以下属性和方法:
■ 属性: x坐标, y坐标
■ 方法: 1.设置x,y的坐标值; 2.输出坐标的信息。
实现代码:
上段代码中定义了一个名为 Point 的类, 具有两个私密属性, int型的xPos和yPos, 分别用来表示x点和y点。
静态常量整型(包括char,bool)数据成员可以直接在类的定义体中进行初始化,例如:
void Test1(Screen& a){};
class LinkScreen
{
Screen window;
LinkScreen* next;
LinkScreen* prev;
}; //注意,分号不能丢
class LinkScreen{ /* ... */ };
public:
Screen& set(char);
};
contents[cursor] = c;
return *this;
}
(2)在类内部声明,加上inline关键字,在类外部定义。
(3)在类内部声明,在类外部定义,同时加上inline关键字。注意:此种情况下,内联函数的定义通常应该放在类定义的同一头文件中,而不是在源文件中。这是为了保证内联函数的定义在调用该函数的每个源文件中是可见的。
二、构造函数是特殊的成员函数,用来保证每个对象的数据成员具有合适的初始值。
构造函数名字与类名相同,不能指定返回类型(也不能定义返回类型为void),可以有0-n个形参。
与其他函数一样,构造函数具有名字、形参表和函数体。
初始化列表比构造函数体先执行。不管成员是否在构造函数初始化列表中显式初始化,类类型的数据成员总是在初始化阶段初始化。
没有默认构造函数的类类型的成员,以及 const 或引用类型的成员,必须在初始化列表中完成初始化。
每个成员在构造函数初始化列表中只能指定一次。重复初始化,编译器一般会有提示。
成员被初始化的次序就是定义成员的次序,跟初始化列表中的顺序无关。
3.3 初始化式表达式
Sales_item(const std::string &book, int cnt, double price): isbn(book), units_sold(cnt), revenue(cnt * price) { }
3.4 类类型的数据成员的初始化式
初始化类类型的成员时,要指定实参并传递给成员类型的一个构造函数,可以使用该类型的任意构造函数。
Sales_item(): isbn(10, '9'), units_sold(0), revenue(0.0) {}
在类A的构造函数初始化列表中没有显式提及的每个成员,使用与初始化变量相同的规则来进行初始化。
class A
{
public:
int ia;
B b;
};
A类对象A a;不管a在局部作用域还是全局作用域,b使用B类的默认构造函数来初始化,ia的初始化取决于a的作用域,a在局部作用域,ia不被初始化,a在全局作用域,ia初始化0。
为所有形参提供默认实参的构造函数也定义了默认构造函数。例如:
{
public:
char c1;
};
5.1 只含单个形参的构造函数能够实现从形参类型到该类类型的一个隐式转换
通过将构造函数声明为 explicit,来防止在需要隐式转换的上下文中使用构造函数:
1.1 几个要点
(3) 复制控制
对于内置类型,例如int, double等,直接初始化和复制初始化没有区别。
对于类类型:直接初始化直接调用与实参匹配的构造函数;复制初始化先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象。直接初始化比复制初始化更快。
(5)形参和返回值
vector<string> svec(5);
编译器首先使用 string 默认构造函数创建一个临时值,然后使用复制构造函数将临时值复制到 svec 的每个元素。
(7)构造函数与数组元素
如果使用常规的花括号括住的数组初始化列表来提供显式元素初始化式,则使用复制初始化来初始化每个元素。根据指定值创建适当类型的元素,然后用复制构造函数将该值复制到相应元素:
Sales_item primer_eds[] = { string("0-201-16487-6"),
string("0-201-54848-8"),
string("0-201-82470-1"),
Sales_item()
};
如果没有定义复制构造函数,编译器就会为我们合成一个。
合成复制构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本。
逐个成员初始化:合成复制构造函数直接复制内置类型成员的值,类类型成员使用该类的复制构造函数进行复制。
例外:如果一个类具有数组成员,则合成复制构造函数将复制数组。复制数组时合成复制构造函数将复制数组的每一个元素。
最好显式或隐式定义默认构造函数和复制构造函数。如果定义了复制构造函数,必须定义默认构造函数。
有些类需要完全禁止复制。例如,iostream 类就不允许复制。延伸:容器内元素不能为iostream
为了防止复制,类必须显式声明其复制构造函数为 private。
与复制构造函数一样,如果类没有定义自己的赋值操作符,则编译器会合成一个。
(2)合成赋值操作符
一般而言,如果类需要复制构造函数,它也会需要赋值操作符。
构造函数的用途之一是自动获取资源;与之相对的是,析构函数的用途之一是回收资源。除此之外,析构函数可以执行任意类设计者希望在该类对象的使用完毕之后执行的操作。
(1) 何时调用析构函数
- 撤销(销毁)类对象时会自动调用析构函数。
- 变量(类对象)在超出作用域时应该自动撤销(销毁)。
- 动态分配的对象(new A)只有在指向该对象的指针被删除时才撤销(销毁)。
- 撤销(销毁)一个容器(不管是标准库容器还是内置数组)时,也会运行容器中的类类型元素的析构函数(容器中的元素总是从后往前撤销)。
如果类需要定义析构函数,则它也需要定义赋值操作符和复制构造函数,这个规则常称为三法则:如果类需要析构函数,则需要所有这三个复制控制成员。
(3)合成析构函数
友元不是授予友元关系的那个类的成员,所以它们不受声明出现部分的访问控制影响。
static 成员遵循正常的公有/私有访问规则。
(1) static 成员的名字是在类的作用域中,因此可以避免与其他类的成员或全局对象名字冲突。
(2) 可以实施封装。static 成员可以是私有成员,而全局对象不可以。
(3) 通过阅读程序容易看出 static 成员是与特定类关联的,这种可见性可清晰地显示程序员的意图。
在类的内部声明函数时需要添加static关键字,但是在类外部定义函数时就不需要了。
因为static 成员是类的组成部分但不是任何对象的组成部分,所以有以下几个特点:
1) static 函数没有 this 指针
2) static 成员函数不能被声明为 const (将成员函数声明为 const 就是承诺不会修改该函数所属的对象)
static 数据成员可以声明为任意类型,可以是常量、引用、数组、类类型,等等。
static 数据成员必须在类定义体的外部定义(正好一次),并且应该在定义时进行初始化。
double Account::interestRate = 0.035;
静态常量整型数据成员可以直接在类的定义体中进行初始化,例如:
static const int period = 30;
(1)static 数据成员的类型可以是该成员所属的类类型。非 static 成员只能是自身类对象的指针或引用
class Screen
public:
// ...
private:
static Screen src1; // ok
(2)非 static 数据成员不能用作默认实参,static 数据成员可用作默认实参
public:
Screen& clear(char = bkground);
private:
static const char bkground = '#';//static const整形变量可以在类内部初始化。
};