类与对象
一、 定义类和对象
1. 一般形式:
class 类名 定义类时首字母要大写;
{
public;公有段数据成员和成员函数
protected;保护段数据成员和成员函数
private;私有段数据成员和成员函数
}; 此处分号不可省略!!!
Private用于声明私有成员。私有成员只能在类中可见,不能在类外或派生类中使用。
2. 返回类型 类名::函数名(参数表)
作用域区分符由两个冒号构成,它用于标识属于什么类的成员。
3.成员函数:类的成员函数是实现类的行为属性的成员。
3.一般将成员函数声明为函数原型,在类外具体实现成员函数。
●必须在定义了类之后,才可以定义类的对象。
4.下面是一个简单的类。
class Student //以class开头
{
intnum;
charname[20];
charsex; //以上3行是数据成员
voiddisplay( ) //这是成员函数
{
cout<<"num:"<<num<<endl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;
//以上4行是函数中的操作语句}
}
};
Student stud1,stud2; //定义了两个Student 类的对象stud1和stud2
二、 访问对象成员
只有公有成员在类体系外可见。
对象成员的访问形式与访问结构的形式相同,运算符“.”和“->”用于访问对象成员。
圆点:对象名.公有成员
指针: 对象指针变量名->公有成员
三、 例题
题目:写一个程序,输入矩形的长和宽,输出面积和周长
分析:将长、宽变量和设置长,宽,求面积,以及求周长的三个函数“封装”在一起,就能形成一个“矩形类”。
长、宽变量成为该“矩形类”的“成员变量”,三个函数成为该类的“成员函数”。
代码实现:class Jvxing
{
public:
intw,h;
intArea()
{
return w * h; //面积
}
int ZC()
{
return 2 * ( w + h); //周长
}
void Init( int w_,int h_ )
{
w = w_; h = h_;
}
}; //必须有分号
intmain( )
{
int w,h;
Jvxing r; //r是一个对象
cin >> w >> h;
r.Init( w,h);
cout << r.Area() << endl <<r. ZC();
return 0;
}
注
1.在类的定义中不能对数据成员进行初始化。
2.类的任何成员都必须指定访问属性,一般将数据成员定义为私有成员或保护成员,将成员函数定义为公有成员。
3.类中的数据成员可以是C++语法规定的任意数据类型。
4.类的成员可以是其他类的对象,称为类的组合。但不能以类自身的对象作为本类的成员。
5.类定义必须以分号“;”结束
6.class与struct的不同:
(1)class中,成员缺省情况是private。
(2)struct中,成员缺省情况是public。
三、内联函数
1.内联函数作用
减少频繁调用小子程序的运行的时间开销
2. 内联函数机制
编译器在编译时,将内联函数的调用以相应代码代替
3. 内联函数声明
inline 函数原型
注:内联函数仅在函数原型作一次声明。
适用于只有1 ~ 5行的小函数
不能含有复杂结构控制语句 ,不能递归调用
例如:
classCoord{
public:
void setCoord(int a,int b)
{ x=a; y=b;}
int getx()
{ return x;}
int gety()
{ retrun y;}
private:
int x,y;
};
四、 构造函数与析构函数
构造函数名与类名相同。构造函数可以有任意类型的参数,但不能有返回类型,构造函数在建立类对象时自动调用。
析构函数名是在类名之前冠以一个波浪号“~”。析构函数没有参数,也没有返回类型。
原型:
类名::类名(参数表);
类名::~类名()
五、 带参数的构造函数
带参数的构造函数可以在建立一个对象时,用指定的数据初始化对象的数据成员。(必须用参数初始化)
六、 重载构造函数
函数名相同,但是参数不同(类型不同或者个数不同)的一组函数。
七、 复制构造函数
特点:
1.复制构造函数名与类名相同,并且也没有返回值类型。
2.复制构造函数可写在类中,也可以写在类外。
3.复制构造函数要求有一个类类型的引用参数。
4.如果没有显式定义复制构造函数,系统自动生成一个默认形式的复制构造函数。
浅复制:
利用系统自带的复制函数,只能用于数据成员是简单数据成员时,不需要自己重新写复制构造函数。例如:
1. #include <iostream>
2.
3. using namespace std;
4.
5. class Box
6.
7. {
8.
9. public:
10.
11. Box();
12.
13. Box(int , int , int );
14.
15. int volume();
16.
17. private:
18.
19. int length, height, width;
20.
21. };
22.
23. Box::Box(int h, int w, int l):length(l),width(w),height(h) { }
24.
25. int Box::volume ()
26.
27. {
28.
29. return width*height*length;
30.
31. }
32.
33. int main()
34.
35. {
36.
37. Box box1(1,2,3);
38.
39. Box box2(box1);//调用系统自带的复制构造函数
40.
41. Box box3=box2;
42.
43. cout<<"Box1's volumeis "<<box1.volume()<<endl;
44.
45. cout<<"Box2's volumeis "<<box2.volume()<<endl;
46.
47. cout<<"Box3's volumeis "<<box3.volume()<<endl;
48.
49. return 0;
50.
51. }
深复制:
当数据成员资源是由指针指示的堆,系统复制对象时只进行(地址值)复制,而不会重新分配内存。这样程序运行时会产生对象操作异常:另外,当对象作用域结束后,又会错误地重复释放堆。所以,这种情况下,需要我们自己写复制构造函数。
格式:类名::(const 类名 & 引用名,…);
八、 类的其他成员
类定义中除了一般指定访问权限的成员,还可以定义各种特殊用途的成员。
1.常成员
2.静态成员
3.友元
(一)常成员
//常数据成员是指数据成员在实例化被初始化后,其值不能改变。
//在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数
//使用const说明的数据成员称为常数据成员。
//如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员赋值。
(二)常对象
//如果在说明对象时用const修饰,则被说明的对象为常对象。
//常对象的说明形式如下:
类名 const 对象名[(参数表)];
或者
const 类名 对象名[(参数表)];
//在定义常对象时必须进行初始化,而且不能被更新。
说明:
(1)C++不允许直接或间接更改常对象的数据成员。
(2)C++规定常对象只能调用它的常成员函数、静态成员函数、构造函数(具有公有访问权限)。
(三)常成员函数
//在类中使用关键字const说明的函数为常成员函数,常成员函数的说明格式如下:
类型说明符 函数名(参数表) const;
const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。
常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外)
2.静态成员
//类成员冠以static声明时,称为静态成员。
//静态数据成员为同类对象共享。
//静态成员函数与静态数据成员协同操作。
//静态成员不属于某一个单独的对象,而是为类的所有对象所共有。
//静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员: 保证在不依赖于某个对象的情况下,访问静态数据成员
//公有访问权限的静态成员,可以通过下面的形式进行访问:
类名::静态成员的名字
对象名.静态成员名字
对象指针->静态成员的名字
在静态成员函数内部,直接访问。
#include<iostream>
using namespace std ;
class counter
{ static int num ;
public:
void setnum (int i) {num = i;}
void shownum(){cout<<num<<'\t';}
};
int counter::num = 0 ;
int main ()
{ counter a , b ;
a.shownum() ;
b.shownum() ;
a.setnum(10) ;
a.shownum() ;
b.shownum() ;
cout<<endl ;
}
注:(1)静态成员函数在类外定义时不用static前缀。
(2)静态成员函数主要用来访问同一类中的静态数据成员。
(3) 私有静态成员函数不能在类外部或用对象访问。
(4)可以在建立对象之前处理静态数据成员。
(5)编译系统将静态成员函数限定为内部连接(在其他文件中不可见)。
(6)静态成员函数中是没有this指针的。
(7)静态成员函数不访问类中的非静态数据成员。如有需要,只能通过对象名(或指向对象的指针)访问该对象的非静态成员。
3.友元
//友元可以是一个普通函数、成员函数或者另一个类。
//友元是非对称的,非传递的。
说明:F是A的友元,但A不是F的友元。
B是A的友元,C是B的友元,但C不是A的友元。
(一) 友元函数
在类体中用friend对其(函数B)进行声明,此函数就称为本类(类A)的友元函数。
例如:friend void FriendFun(A * , int) ;
void FriendFun( A * ptr , int x )
{ ptr -> i = x ; } ;
void A:: MemberFun( int x )
{ i = x ; } ;
(二) 友元类
若F类是A类的友元类,则F类的所有成员函数都是A类的友元函数。在程序中,友元类通常设计为一种对数据操作或类之间传递信息的辅助类。
九、 类的包含
//类的包含是程序设计中一种软件重用技术。即定义一个新的类时,通过编译器把另一个类 “抄”进来。
//当一个类中含有已经定义的类类型成员,带参数的构造函数对数据成员初始化,须使用初始化语法形式。
构造函数 ( 形参表 ) : 对象成员1(形参表 ) , …, 对象成员n (形参表 ) ;
十、 心得
类与对象算是首次接触c++吧,感觉和C语言完全不同,由习惯的语言一下转到一个全新的语言模式很不适应,学起来也特别困难。虽然一直在说就是一个框架,一个套路。但是这个套路还是掌握不好。在我看来类与对象最重要的就是定义类这方面。
而且我们在调试程序时需要一步一步的来,每定义一个就写一个主函数,过了就注释掉。继续写下一个定义。这样可以在第一时间找出代码中的错误并修改,不会等到最后面对一百甚至几百个错误发愣。
写程序时我们也需要先分析,这个程序我们需要什么,需要完成什么功能,列出一个大体的提纲。然后按照这个提纲一点一点的定义。这样会省很大的功夫,避免了重复或遗漏功能。