第三章 类与对象.docx
《第三章 类与对象.docx》由会员分享,可在线阅读,更多相关《第三章 类与对象.docx(18页珍藏版)》请在冰豆网上搜索。
第三章类与对象
第三章类与对象
面向对象三部曲:
1、
类的定义
class类名//自定义数据类型
{访问限定符[public/protected/private]:
数据成员;
成员函数;
};
2、
对象的声明
类名对象名;//类的变量、引用
类名对象数组名[数组长度];//数组
类名*对象指针名//指针
3、
对象的引用
对象名.数据成员名
对象名.成员函数名(实参表)
指针:
.换为->
对象指针名->数据成员名
必须是public成员
1、类的定义
class类名
{访问限定符[public/protected/private]:
//
(1)
数据成员;//
(2)
成员函数;//(3)
友元声明;//(4)
};
说明:
(1)访问限定符:
(默认是private)
✧public:
公有成员,对象可访问(引用)的接口。
✧protected:
保护成员,继承时,可以被类的其他成员访问,在单独的类上,同private没区别。
✧private:
私有成员,真正意义上被封装的成员。
继承时,不可访问。
(2)数据成员:
A、基本数据类型变量、指针等均可作为成员
B、其他类的对象(类对象成员,也称为子对象)
●拥有类对象成员的类,其构造函数必须注意到其类对象的构造函数结构.
●构造函数调用顺序:
先调用类对象的构造函数,再调用拥有类对象的类的构造函数.析构函数的调用顺序相反.
●无论类对象的构造函数形式如何,定义拥有类对象的数据时,必须能找出和其构造函数一致的对象声明形式,否则出错.
(a)其类对象是无参形式.(类名对象名;)
无须注意类对象的构造函数.
类(拥有类对象)
类对象
classB
{Aa;
intb;
public:
B(){b=0;}
B(intbb){b=bb;}
};
voidmain()
{Bb1,b2(3);}
classA
{public:
A(){…..}
};
(b)其类对象是有参形式.类名对象名(参数表);
类(拥有类对象)
类对象
classB
{Aa1;
intb;
public:
B(intaa):
a1(aa)
{b=0;}
B(intaa,intbb)
:
a1(aa),b(bb){}
};
voidmain()
{Bb1(3);
Bb2(3,4);
}
classA
{inta;
public:
A(intaa){a=aa;}
};
voidmain()
{Aa1(3);
}
#include
classA
{inta;
public:
A(intaa){a=aa;cout<<"A:
:
A(int)\n";}
A(){a=0;cout<<"A:
:
A()\n";}
~A(){cout<<"A:
:
~A()\n";}
};
classB
{Aa1;
intb;
public:
B(){cout<<"B:
:
B():
a1()\n";}
B(intaa):
a1(aa)
{b=0;
cout<<"B:
:
B(int):
a1(int)\n";
}
B(intaa,intbb)
:
a1(aa),b(bb){
cout<<"B:
:
B(int,int):
a1(int),b(int)\n";
}
~B()
{cout<<"B:
:
~B()\n";}
};
voidmain()
{
Bb1(3);
Bb2(3,4);
Bb3;
}
C、静态数据成员(static)//属于类,类内共享的数据
a)定义(类内):
statictype静态变量名;
b)初始化(类外):
type类名:
:
静态变量名=初始值;
c)引用(public):
对象名.静态数据成员
类名:
:
静态数据成员
d)用途:
用于访问控制.
classA
{staticintresource;//定义
public:
intgetresource()
{if(resource)return0;
else{resource=1;return1;}
}
voidfreeresource()
{resource=0;}
};
intA:
:
resource=0;
voidmain()
{Aa,b;
if(a.getresource)cout<<”a获得了资源\n”;
if(!
b.getresource)cout<<”b无法获得资源\n”;
a.freeresource();cout<<”a释放了资源”;
if(b.getresource)cout<<”b获得资源\n”;
}
-------------------资源有2个时-----------------------
#include
classA
{staticintresource;//定义
public:
intgetresource()
{if(resource==2)return0;
else{resource++;return1;}
}
voidfreeresource()
{resource--;}
};
intA:
:
resource=0;
voidmain()
{Aa,b,c;
a.getresource();
b.getresource();
if(!
c.getresource())cout<<"c无法获得资源\n";
}
用于记数.
#include
classA
{
public:
staticintnum;//定义
A()
{cout<<"构造\n";
num++;
}
~A()
{cout<<"析构\n";
num--;
cout<<"当前对象数:
"<}
};
intA:
:
num=0;
voidmain()
{Aa;
cout<<"当前对象数:
"<:
num<Ab;
cout<<"当前对象数:
"<Ac;
cout<<"当前对象数:
"<}
this指针
classA
{inta,b;
public:
A(intaa,intbb)
{a=aa;b=bb;}
};
A(intaa,intbb)
{this->a=aa;
this->b=bb;
}
类的静态成员函数没有this指针.
classA
{intk;
public:
staticintnum;//定义
A(intkk=0)
{k=kk;
cout<<"构造\n";
num++;
}
staticvoidprint(A&x)
{cout<<"当前对象数:
"<cout<<"k="<}
~A()
{cout<<"析构\n";
num--;
k--;//this->k--;
cout<<"当前对象数:
"<}
};
(3)成员函数:
(凡是类内定义的函数默认是inline函数)
✧函数的定义方式:
A、类内定义
class类名{函数定义};
B、类内声明、类外定义(需加:
类名:
:
)//:
:
作用域访问限定符
class类名{函数声明;};
[inline]T类名:
:
函数名(参数表){.......}
✧特殊的成员函数:
A、常成员函数
格式:
Tf(…)const;
作用:
禁止成员函数修改数据成员的值
B、构造函数(函数名是类名,无返回值类型,系统自动执行,在程序中不可显式调用,有0~n个参数,可重载)
何时调用:
(1)声明对象时,自动执行;
类名对象名;//无参
类名对象名(参数表);//有参
(2)用对象指针new一个对象时,自动执行:
类名*对象指针名=new类名;
格式:
(1)一般形式(无参、有参)
类名(参数表){……}
(2)成员初始化列表形式(有参构造函数用,有些教材也称为:
参数对照表)(成员必须是一般变量,不能初始化列表数组)
类名(参数表):
成员1(初始值),成员2(初始值),…{……}
♦构造函数初始化列表中的成员初始化次序与它们在类中的声明次序相同,与初始列表中的次序无关。
♦构造函数初始化列表先于构造函数体中的语句执行。
♦常量成员,引用成员,类对象成员,派生类构造函数对基类构造函数的调用必须采用初始化列表进行初始化
作用:
用于建立对象时对对象的数据成员进行初始化
分类:
a)默认构造函数(无参):
✓当一个类没有定义任何构造函数,编译器会生成默认构造函数,函数体内为空。
✓在用默认构造函数创建对象时,如果创建的是全局对象或静态对象,则对象所有数据成员初始化为0;如果创建的是局部对象,即不进行对象数据成员的初始化。
b)重定义无参构造函数:
✓一旦定义了任意的构造函数。
系统就不会产生默认构造函数
c)缺省参数的构造函数
✓构造函数可以重载。
与普通函数的重载一样,重载的构造函数必须具有不同的函数原型
d)拷贝构造函数
类名(const类名&){……}
✓是一个特殊的构造函数,用于根据已存在的对象初始化一个新建对象
✓若没有定义类的拷贝构造函数,系统将产生一个默认拷贝构造函数。
默认拷贝构造函数以成员按位拷贝(bit-by-bit)的方式实现成员的复制。
当一个类有指针类型的数据成员时,默认拷贝构造函数常会产生指针悬挂问题。
(浅拷贝)
✓在以下3种情况下拷贝构造函数会被自动调用
♦当用类的一个对象去初始化该类的另一个对象时;
♦当函数的形参是类的对象,进行形参和实参结合时;
♦当函数的返回值是类的对象,函数执行完成返回调用者时。
实例1:
#include
classstudent
{
private:
intnum;
floats1,s2,s3;
floatsum;
public:
student(floata=0.0,floatb=0.0,floatc=0.0):
s2(b),s1(a),s3(c),num(0),sum(0)
{}
student(floata,floatb,floatc,floatn,floats):
s2(b),s1(a),s3(c),num(n),sum(s)
{}
voidsetscore(float,float,float);
voidsumscore()
{sum=s1+s2+s3;
}
voidprint()
{cout<<"num\tscore1\tscore2\tscore3\tsum\n";
cout<}
};
voidmain()
{
studentstu0,//带默认值构造函数
stu1((45,78,56,1002,0),
//有5个参数的构造函数)
stu2(68,78),stu3(78,65,95),*p;
p=&stu0;
p->sumscore();
p->print();
p=&stu1;
p->sumscore
p->print();
p=&stu2;
p->sumscore();
p->print();
p=&stu3;
p->sumscore();
p->print();
studentstu4=stu3;//拷贝构造函数
p=&stu4;
p->sumscore();
p->print();
}
C、析构函数(系统自动执行,在程序中不可显式调用,无参数,可声明为虚函数)
格式:
~类名(){……}
作用:
用于对象生命期结束时回收对象
调用时机:
⏹对象生命期结束时自动调用
⏹自动/局部对象:
定义的语句块结束处
⏹全局对象、静态对象:
程序结束时
⏹delete指针对象时
D、静态成员函数(static)
a)定义:
statictypef(参数表){…..}
b)调用:
对象名.f()类名:
:
f()
注意:
在静态成员函数中不能访问类中的非静态数据成员.如果要访问,需要在成员函数的参数表中带上该类的一个对象名.
#include
classA
{intk;
public:
staticintnum;//定义
A(intkk=0)
{k=kk;
cout<<"构造\n";
num++;
}
staticvoidprint(A&x)
{cout<<"当前对象数:
"<cout<<"k="<}
~A()
{cout<<"析构\n";
num--;
cout<<"当前对象数:
"<}
};
intA:
:
num=0;
voidmain()
{Aa(5);
a.print(a);
Ab(3);
A:
:
print(b);
Ac;
c.print(c);
}
(4)友元声明(会破坏类的封装,授权全权访问)
一个类的友元能够直接访问该类所有成员,包括public、protected、private类型的成员。
✧友元函数
用途:
一般用于运算符重载。
classX{
……
friendTf(…);//友元声明
……
};
……
Tf(…){……}//友元函数的定义、
#include
classA
{private:
inta;
friendvoidprint();
protected:
intb;
public:
intc;
A(intaa,intbb,intcc):
a(aa),b(bb),c(cc){}
};
voidprint()
{Aa1(4,5,6);
cout<}
voidmain()
{
print();
}
✧友元类
一个类可以是另一个类的友元,友元类的所有成员函数都是另一个类的友元函数,能够直接访问另一个类的所有成员。
用于:
多个函数均需成为某类的友元时,将多个函数封装到一个类中。
类中有另一个类的对象成员时。
#include
classA
{private:
inta;
friendclassB;
protected:
intb;
public:
intc;
A(intaa,intbb,intcc):
a(aa),b(bb),c(cc){}
};
classB{
private:
Aa1;
public:
B(intaa,intbb,intcc):
a1(aa,bb,cc){}
voidinput()
{cin>>a1.a>>a1.b>>a1.c;
}
voidprint()
{
cout<}
voidadd()
{cout<}
};
voidmain()
{
Bb1(4,5,6);
b1.input();
b1.print();
b1.add();
}
2、对象的声明
1)对象的形式:
变量、引用、数组、指针。
2)构造函数的形式。
(无参,有参,带默认值,拷贝)
a)无参:
Aa1,&b1=a1,a2[3],*pa=newA,*pb=newA[3];
引用不会调用构造函数,指针只有new对象时才构造。
b)有参(1个):
Aa1
(1),&b1=a1,a2[3]={1,2,3},*pa=newA
(1);
(多个):
数组支持有一个参数。
多个参数时必须有一个参数或无参构造函数的存在才不会出错。
对象指针指向数组时,也不能调用有参构造函数。
注意:
对象的声明形式,必须与其所在类的构造函数对应。
构造函数中至少有一个能符合对象的声明形式时程序才不会出错。
#include
classA
{private:
inta;
protected:
intb;
public:
A(intaa=0,intbb=0):
a(aa),b(bb){}
};
voidmain()
{Aa1(1,1);
A&b1=a1;
Aa2[3]={1,2,3};
A*pa=newA(1,1);
A*pb=newA[3];
}
3、对象的访问(即用对象名去访问类的public成员)
对象名.成员
引用名.成员
对象指针->成员
4、对象的应用:
(封装性不变,只能访问public成员)
作为函数的参数
作为函数的返回值
编程应用:
接口与实现的分离
类的定义(只有成员函数的声明)-----某名.H文件
类的实现(成员函数的定义)------某名.cpp文件---静态库。
对象的声明及引用------------------.cpp文件(必须用文件包含命令将类的定义及实现文件包含进来)