类的基本知识
一、类的定义
基本语法:
class 类名
{
类体。
};
类内总共有两种成员,数据成员,成员函数。
二、类的成员的访问修饰符(public private protected)
每个类的成员均有访问修饰符,默认是private.
基本语法:
访问修饰符:
成员定义
或者单独对每个成员加上一个访问修饰符。
以下只讨论类内和对象对成员的访问,不介绍友元和继承对成员的访问:
public :类内和对象均可以使用,派生类也可以访问。
private:只有类内可以使用。(成员函数中的本类的对象也可以访问),在派生类
中不可访问。
protected:类内可以使用,以及派生类中可以访问。
三、类的静态成员(static修饰)
总共有两种成员:静态数据成员,静态成员函数。
类的静态成员,在内存中只有一份,而且不会随着对象的销毁而释放。
1、static数据成员(类内声明,类外定义(初始化))
独立于该类的任意对象而存在,在外部使用时,用类引用,也可以用对象引用
,但用类引用该static数据成员显得更加的清晰。可以通把static成员定义为
私有成员,防止外部访问。
在类外初始化的基本语法:
类型 类名::成员变量=值;
2、static成员函数
在成员函数面前,加上static修饰,在静态函数中,不可以使用this指针
,也不可以使用非静态的成员变量,只可以使用类的静态成员变量,以及类
的静态成员函数。
二、成员函数的定义与实现
在程序设计中,为了体现类的结构清晰,通常在头文件中只放置类的定义,而类成
员函数的实现通常放在.CPP文件中。
将定义放在头文件中,在实现文件中包含该类定义所在的头文件,在使用该类的文件中。
包含该头文件 。或者使用namespace实现。
类外实现:
返回类型 类名::函数名(形参列表)
{
函数体
}
三、构造函数
基本语法:
类名(形参表):成员变量(值),成员变量(值),..
{
成员初始化
}
注:如果一个类没有定义构造函数,那么编译器会自动添加一个无参的默认构造函
数。但是如果一旦定义了一个构造函数,编译器便不坐再添加默认构造函数。
成员变量的初始化只能出现一次。构造函数的形参可以有默认值。从右向左。
静态数据成员不可以在初始化列表中初始化。
四、复制构造函数与赋值操作符(=)
1、复制构造函数
使用同类型的对象构造一个新的对象。同构造函数一样,如果一个类没有定义复制
构造函数,编译器会自动添加一个复制构造函数,不过一个类只能有一个复制
构造函数。复制构造函数一般使用对象常引用做形参。
基本语法:
类名(const 类名 & 形参对象名)
{
复制构造函数体
}
程序调用复制构造函数的3种情况:
1、定义类对象的时候直接用其他对象初始化,如:Student s1=s2;
2、调用函数的时候,若形参为类类型,且没有定义为引用或者指针,这时
是值传递,编译器会自动为传入的实参创建一个复制给形参。
3、在函数返回的时候,如果函数的返回类型为类型,且没有定义为引用,
那么在函数返回的时候,编译器也会用一个复制返回,都属于值传递。
注:当复制对象时,成员中有指针变量时,不能复制指针值,而要重新申请一段内存
并将指向中的内存中的值复制到这里面来,然后用一个新的指针指向这段内存。
但是默认的复制构造函数做不到,只是浅复制。所以需要自定义,实现深复制。
2、赋值操作符(=)
编译器默认会类添加一个赋值操作符 =,但是,同样只能完成数据成员值的赋值,
并不能实现深层复制。
基本语法:
类名 & operator = ( 参数)
{
函数体
return *this;
}//一般参数是常类对象引用。
注:重载赋值操作符必须定义为类的成员函数,可多个。
赋值操作符与复制构造函数的区别:
赋值 发生在两个已经存在的对象间如:
Student s1(“TOM”);
Student s2;
s2=s1;
复制构造函数 用一个已经存在的对象来实例化一个新对象。
Student s1;
Student s2(s1);
Student s3=s1;
五、析构函数
一个类只能有一个析构函数,编译器自动为没有定义析构函数的类,生成一个析构函数,
不进行任何操作(所以如果有指针或者打开的文件之类的,就一定要自定义析构函数)。
基本语法:
~类名()
{
}
六、运算符重载(也称操作符重载)
基本语法:
返回类型 operator 操作符(参数列表)
{
函数体
}
定义操作符重载函数时,有三种定义方式:1、成员函数 2、全局函数 3、友元函数
一般用成员函数和友元函数。
1、操作符重载函数定义为成员函数
操作符的第一个参数是调用该操作符的对象。(并且不在形参列表中出现。)
2、定义为友元函数
操作符的所有参数都必须在形参列表中给出。
参数列表中参数的个数取决于两个因素
1、操作符是一元操作符,还是二元,还是多元操作符
2、操作符函数是类成员函数还是全局函数,或者友元函数。
下面有几个例子:
输入输出运算符的重载
1、输出运算符的重载 <<
语法:
ostream & operator <<(ostream & out,const 类名 &形参对象)
{
out<<...
return out;
}
2、输入运算符的重载 >>
istream & operator >>(istream &in,const 类名 &形参对象)
{
in>>...
return in;
}
注:必须把这两个运算符重载函数定义为类的友元函数,因为该操作符的第一个
参数必须是i/ostream对象,所以如果定义成成员函数,那么必须定义在
ostream 和istream类中,这样才能将这个对象当作第一个参数,
但是这两个是系统标准库的组成部分,不可修改。
自定义数据类型转换
注:
C++ 中explicit 关键字的作用在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换
1、构造函数转换
类名(源类型 变量名)
{
函数体
}
如:int型到Student类的转换
Student (int n)
{
}
2、操作符转换
语法:无返回类型,因为返回的类型就是类型名。
operator 类型名()
{
函数体
}
如:
Student类中:
operator char *()
{
}
将Student 类型转换成char *
两者的区别:
1、构造函数定义在目标类型中:将某个数据类型转换为相应的类类型
2、操作符转换函数定义在源类型的类中:将类型转换为相应的目标类型
七、类的友元
友元:允许特定的非成员函数访问一个类的私有成员,同时仍然阻止一般的
访问。
两种友元:友元类 友元函数
友元的声明以friend开始,而且只能出现在类的内部,但定义可以在外面。
1、友元类
整个友元类中的函数都可以访问该 类的所有成员
2、友元函数
可以是普通的函数,也可以是某个类的一个成员函数。
友元函数在外部定义时,不需要加上类名,因为它并不是类的成员。
八、访问对象中的成员
对象.成员
(*对象指针) .成员
对象指针->成员
九、常对象与类中的常成员。
常对象:常对象的数据成员值在对象的整个生存期内不能改变,而且在定义
对象时必须进行初始化。
声明基本语法:const修饰
类名 const 对象名(参数列表);
或者
const 类名 对象名(参数列表);
常数据成员:const修饰,只能通过构造函数的初始列表对该数据成员进行初始化
,而其他任何函数都不能对该成员赋值。且值不可变
常成员函数:在声明函数和定义函数时都要有关键字const,常成员函数不能更新
对象中的数据成员,也不能调用该类中的普通成员函数
声明语法:
返回类型 函数名(参数表) const;
注:如果将一个对象声明为常对象,则通过该对象只能调用它的常成员函数,而不能调用普通
的成员函数,常成员函数是常对象惟一的对外接口。