C++核心技术篇(五)

this指针

对于类的非静态成员,每个对象都有自己的一份拷贝,即每个对象都有自己的数据成员,不过成员函数却是每个对象共享的。那么调用共享的成员函数是如何找到自己的数据成员呢?答案是通过类中隐藏的this指针。下面通过一个例子来说明this指针的作用。
同一个类的不同对象数据

class CBook{     //定义一个CBook类;
public: 
int m_Page;     //定义一个数据成员
void OutputPages(){     //定义一个成员函数
cout<<m_Pages<<endl;       //输出信息
}
};
int main(int argc,char* argv[])
{
CBook vbBook,vcBook;    //定义两个CBook类对象
vbBook.m_Pages=512;      //设置vbBook对象的成员数据
vcBook.m_Pages=570;      //设置vcBook对象的成员数据
vbBook.OutputPages();     //调用OutputPages方法输出vbBook对象的数据成员
vbBook.OutputPages();
return 0;

从运行结果看,两个对象均有自己的数据成员m_Pages,在调用OutputPages成员函数时均输出自己的数据成员。
实际上编译器为了实现this指针,在成员函数中自动添加了this指针对数据成员的方法,类似于上面的OutputPages方法。此外使this指针指向当前调用对象,并能够在成员函数中使用,在每个成员函数中都隐藏着一个this指针作为函数参数,并在函数调用时将对象自身的地址隐含作为实际参数传递。

对象与复制

当函数已相应的类作为形参列表时,对象可以作为函数的参数传入。在学习函数时,我们曾提到过,值传递先复制实参产生副本。那么,对象的副本又是怎样的呢?
复制构造函数是指类的对象被复制时所调用的函数。下面两种情况中对象都会调用复制构造函数
将一个对象复制给另一个对象时,例如

对象1=对象2//对象1与对象2所属类相同
对象1(对象2)

上面的程序中对象2的复制构造函数会被调用
作为值的实参

function(对象1);

在function函数体内,使用的是对象1的副本,所以之前会调用对象1的复制构造函数。
和构造函数一样,C++在为发现自定义的复制构造函数之前会创建一个默认的构造函数
自定义的赋值构造函数的声明格式为:

类名(类名& 形参)

值得注意的是,复制构造函数是引用传递的函数。既然默认赋值构造函数已经完成复制工作,那么何时需要重新定义他呢?例如,一个类具有指针类型的数据,默认赋值构造函数执行之后,原对象和副本的指针成员指向的是同一个内存空间。通过指针改变该内存,就会改变两个对象实际应用的数据(也就是这块内存的内容)。这时可以自定义赋值构造函数,将两个指针的内存分离开。
菌类的繁殖
germ.h中声明了一个菌类,代码如下:

#include<string>
using std::string;
class germ{
public:
int m_age;
string m_name;
germ(germ& g);
germ(string s);
~germ();
};

germ.cpp中实现了菌类,代码如下:

#include"stdafx"
#include2"germ.h"
#include<iostream>
using std::cout;
using std::endl;
germ::germ(string s){
m_name=s;
m_age=1;
cout<<"发现了"<<m_name<<endl;
}
germ::germ(germ& g){
g.m_age+=1;
this->m_age=1;
this->m_name=g.m_name+"的复制体";
cout<<"产生了"<<g.m_name<<"的复制体"<<endl;
}
germ::~germ(){
cout<<this->m_name<<"被消灭了"<<endl;
}

main.cpp程序的入口如下:

#include"stdafx.h"
#include<iostream>
#include"germ.h"
using std::cout;
using std::endl;
germ copyGerm(germ gc){
return gc;
}
int main(){
germ g1("有氧菌");
germ g2(g1);
germ g3("无氧菌");
germ g4=g3;
germ g5=copyGerm(g4);
return 0;
}

从程序运行结果来分析代码:首先在主函数产生了g1对象,由复制构造函数产生了g1的赋值体g2——有氧菌复制体。之后定义了g3——无氧菌。通过复制构造函数产生了g3的复制体g4.前四行输出即是上面所述的过程。g5的产生前,g5所在的赋值语句等号右边的copyGerm函数被调用,传递的实参为g4——无氧菌的复制体。如同本节开始提到的,值传递实参对象产生副本,副本就是形参gc——无氧菌复制品的复制体。函数执行完毕后,传递会临时变量,内容是gc。g5的值经过赋值语句,所以他是gc(临时变量使用的内存)的复制品。

const对象

当创建一个对象之后,如果不希望它的任何数据发生改变,可以将其直接声明为const对象,例如:

const 类名 对象名

值得注意的是,const对象必须初始化。依照之前的一贯说法,这是一个只读对象。我们可以调用他的数据和函数,但是不可以对他进行修改。除此之外,const对象的this指针也是常量。在上一节中曾经提到过,成员函数在自己的函数体内自动为成员变量加上了this指针。如何使这些内存指针转化为const呢?仍然需要const关键字,函数声明形式如下:

返回类型 函数名(参数列表) const;

值得注意的是,const对象必须初始化。依照之前的一贯说法,这是一个只读对象。我们可以调用他的数据和函数,但是不可以对他们进行修改。除此之外,const对象的this指针也是常量。在上一节中曾经提到过,成员函数在自己的函数体内自动为成员变量加上了this指针。如何使用这些内存指针转化为const呢?仍需要const关键字,函数声明如下:

返回类型 函数名(参数列表) const;

即在函数头结尾加上const。只能对类中的函数做如此声明,对外部的函数无效。
下面用一个实例进一步说明const对象的使用方法。
标准尺寸
box.h的代码如下:

class box{
public:
int m_lenth;
int m_width;
int m_hight;
box(int lenth,int width,int hight);
bool Compare(box b) const;
};

box.cpp的代码如下:

#include“stdafx"
#include<iostream>
#include"box.h"
using std::cout;
using std::endl;
box::box(int lenth,int width,int hight){
m_lenth=lenth;
m_width=width;
m_hight=hight;
cout<<"刚刚制作的盒子长:"<<lenth<<"宽:"<<width<<"高:"<<hight<<endl;
}
bool box::Compare(box b)const{
return (m_lenth==b.m_lenth)&(m_width==b.m_width)&(m_hight==b.m_higt);
}

main.cpp程序入口的代码如下:

#include"stdafx.h"
#include"box.h"
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
int main(){
const box styleBox(4,2,3);
cout<<"Standard boxs are created"<<endl;
box temp(1,1,1);
while (styleBox.Compare(temp)!=true){
cout<<"The box doesn't fit"<<endl;
int lenth;
int width;
int hight;
cout<<"Please enter the data of the new box to make it fit the standard box size"<<endl;
cin>>lenth;
cin>>width;
cin>>hight;
temp=box(lenth,width,hight);
}
cout<<"The box just fits.Congratulations"<<endl;
return 0;
}

对象数组

在数组内容中我们了解到,数组是通过指针分配到的一段额定

大小的空间。同样,数组也是可以包含对象。声明对象数组的形式如下:

box boxArray[5];
box boxArray2[2]={box(1,1,1),box(2,2,2)};
box boxArray3[3]=(3,styleBox);

值得注意的是,第一种申请对象数组的方法必须保证类中含有默认的构造函数,否则编译器会报错。同样通过对象指针申请动态对象数组。例如:

box* pbox;
[pbox=new box[n];

同时需要确认box中默认构造函数
box.h的代码如下:

class box{
public:
//class member variable(类成员变量)
float m_lenth;
float m_width;
float m_hight;
int Number;
//class member function(类成员函数)
box(float lenth,float width,float hight);
}

box.cpp的代码如下:

#include"stdafx.h"
#include<iostream>
#include"box.h"
using std::cout;
using std::endl;
box::box()
{
m_lenth=1.000f;
m_width=1.000f;
m_hight=1.000f;
cout<<"make the length of the box:"<<m_lenth<<"width:"<<m_width<<"hight"<<m_hight<<endl;
}
box::box(float lenth,float width, float hight){
m_lenth=lenth;
m_width-width;
m_hight=hight;
cout<<"Custom box lenth:"<<lenth<<"width:"<<width<<"hight:"<<hight<<endl;
}
bool box::Compare(const box b) const{
return (m_lenth==b.m_lenth)&(m_width==b.m_width)&(m_hight==b.m_hight);
}
void box::ToCheck(){
cout<<"this box is now long"<<m_lenth<<"width:"<<m_width<<"hight:"<<m_hight<<endl;
}
void box::Rebuild(float lenth,float width,float hight){
m_lenth=lenth;
m_width=width;
m_hight=hight;
}

程序入口main.cpp的代码如下:

#include"stdafx.h"
#include"box.h"
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
bool check(float a,float b,float c){
return (a>0)&(b>0)&(c>0)&(a<100)&(b><00)&(c<100);
}
int main(){float lenth;
float hight;
float width;
cout<<"please enter the lenth,width and hight of thr box you need:"<<endl;
while(cin>>lenth,cin>>hight,cin>>width,!check(lenth, width,hight))
{
cout<<"sorry, the speclification you input is beyond our production level, please input again"<<endl;
}
const box styleBox(lenth,width,hight);
cout<<"please enter the number of our order"<<endl;
int count;
while(cin>>count,!((count>0)&(count<6)))
{
if(count>5){
cout<<"sorry that the amount of the order exceeds the production level, please enter again"<<endl;
}
else{
cout<<"please enter again"<<endl;
}
}
box* boxArray;
boxArray=new box(count);
bool bOk=false;
for(int i=0;i<count;i++){
boxArray[i].Rebuild(lenth.width,hight);
boxArray[i].ToCheck();
if(styleBox.Compare(boxArray[i])){
cout<<"this product conforms to speclification"<<endl;
}
}
delete []boxArray;
return 0;
}

程序中将长宽高定义为浮点数类型,如果输入超过精度,则会将超过精度的最后一位四舍五入的方式进位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

茫渡。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值