本篇文章将介绍对象数组,对象的动态分配以及对象在函数中的应用。

一、对象数组

1、对象数组的定义和初始化

  定义对象数组与定义普通数组的语法形式基本相同。如定义一个Square obj[3];表示一个正方形类的对象数组,数组元素为三个。将该数组初始化:Square[3]={Square(2),Square(3),Square(4)};

  对象初始化的表示形式是“类名(参数列表)”。计算机在执行对象数组定义语句时,数组中有多少元素,就会调用多少次构造函数。

2、对象数组的访问

  对象数组的每个元素都是一个对象,都有各自的成员。可以访问各种对象元素的公有成员,访问形式:对象数组名[下标].公有成员名; 当然也可以通过指针访问:Square *p = obj;p->Area();

3、对象数组的析构

  销毁对象数组,就是逐个销毁其中的所有对象元素。换句话说,计算机销毁对象数组时,数组中有多少个元素,就会调用多少次析构函数。

二、对象的动态分配

  C++可以使用内存分配方法定义对象或对象数组。new运算符动态分配内存,内存使用完之后通过delete运算符即时释放,提高内存利用率。内存的动态分配、访问以及释放需要通过指针变量才能实现。

1、单个对象的分配与释放

  首先预定义一个类类型指针用来保存分配空间的首地址,后续访问内存单元时将使用该对象指针进行间接访问。动态分配类的对象时会自动调用该类的构造函数,删除对象时自动调用类的析构函数。

  方法一:

  Square *p;

  p = new Square;   //分配一个类Square的对象,用p保存所分配内存额首地址

  delete p;

  方法二:

  Square *p;  p = new Square(2);delete p; // 分配一个类Square的对象,并将其边长初始化为2

  方法三:

  Square *p = new Square(2);delete p;

2、对象数组的分配与释放

  动态分配对象数组时,数组中有多少个元素就会调用多少次析构函数。删除对象数组时,数组中有多少个元素就会调用多少析构函数。

Square *p; //预定义指向对象数组首地址的指针
p =new Square[3];//分配一堆对象数组,包含3个元素
p[0].a=2; cout<<p[0].Area();
(p+1)->a=3;cout<<(p+1)->Area();//通过指针访问数组元素的成员 delete []p;//释放p 所指向的一组对象

三、对象作为函数的形参

  与变量一样,函数间传递对象时也存在值传递、引用传递和指针传递。

1、值传递与常对象

  对象在函数间的值传递实际上时重构了一个对象形参,将实参对象复制到形参对象中。对于只读不改的对象可以定义为常对象。常对象在定义时必须初始化,定义后不能在修改其数据成员。

2、引用传递与常引用

  引用传递将被调函数的对象形参定义成主调函数中对象实参的引用,被调函数通过该引用间接访问主调函数中的对象。被调函数对引用的修改都会影响主调函数中实参对象的值。为了避免这种传递带来的互相影响,我们可以将被调函数的形参定义为常引用。常引用定义后,被调函数任何想要通过其形参修改主调函数实参值的操作都会提示错误,不被允许。

  注意:引用传递时函数间传递对象最常用的方式,原因在它不需要额外申请空间,可以互相传值,还可以通过常引用避免形参改变影响实参。

3、指针传递与指向常对象的指针

  指针传递就是将主调函数中的对象实参的内存地址传递给被调函数的对象指针形参,被调函数通过该地址间接访问主调函数的对象。和引用传递一样形参同样可以改变实参,为了避免这样传递带来的互相影响,可以将被调函数的形参定义为指向常对象的指针。定义成指向常对像的指针后,被调函数任何想要通过其指向常对象的指针形参修改主调函数实参值的操作都会提示错误,不被允许。

  下面通过一个实例来介绍这六种对象传参方法:

#include<iostream>
using namespace std;
//类定义
class Square
{
public:
double a; //数据成员a表示:正方形边长
double Area() //内联函数Area():求正方形面积
{
return(a*a);
}
Square(double x = 0) //带默认形参值的构造函数
{
a=x;
}
};
//求正方形对象s的内切圆面积
double InnerCircleArea1(Square s) //值传递
{
s.a=4;
double r = s.a/2;
return (3.14*r*r);
} double InnerCircleArea2( const Square s) //常对像值传递
{
//s.a=4; 形参为常对象,不得修改常对象的成员值
double r = s.a/2;
return (3.14*r*r);
}
double InnerCircleArea3(Square &s) //引用传递
{
s.a=4;
double r = s.a/2;
return (3.14*r*r);
}
double InnerCircleArea4(const Square &s) //常引用对象传递
{
//s.a=4; 形参为常引用对象,不得修改常引用对象的成员值
double r = s.a/2;
return (3.14*r*r);
}
double InnerCircleArea5(Square *s) //指针传递
{
s->a=6;
double r = s->a/2;
return (3.14*r*r);
}
double InnerCircleArea6(const Square *s) //指向常对象的指针传递
{
//s->a=6; 形参为指向常对象的指针,不得通过常对象指针修改所指对象的成员值
double r = s->a/2;
return (3.14*r*r);
}
int main()
{
Square obj(2);
cout <<"值传递: "<< InnerCircleArea1(obj) << endl; //初始边长为2,函数内修改a为4
cout <<"常量值传递:"<< InnerCircleArea2(obj) << endl; //初始边长为2,函数内修改a为4,语法错误
cout <<"引用传递: "<< InnerCircleArea3(obj) << endl; //初始边长为2,函数内修改a为4
cout <<"常引用传递:"<< InnerCircleArea4(obj) << endl; //初始边长为2,函数内修改a为4,语法错误
cout <<"指针传递: "<< InnerCircleArea5(&obj) << endl; //初始边长为2,函数内修改a为6
cout <<"常指针传递:"<< InnerCircleArea6(&obj) << endl; //初始边长为2,函数内修改a为6,语法错误 return 0;
} 对象函数传递示例

函数中的对象传递

#include<iostream>
using namespace std;
//类定义
class Square
{
public:
double a; //数据成员a表示:正方形边长
double Area() //内联函数Area():求正方形面积
{
return(a*a);
}
Square(double x = 0) //带默认形参值的构造函数
{
a=x;
}
};
//求正方形对象s的内切圆面积
double InnerCircleArea1(Square s) //值传递
{
s.a=4;
double r = s.a/2;
return (3.14*r*r);
} double InnerCircleArea2( const Square s) //常对像值传递
{
//s.a=4; 形参为常对象,不得修改常对象的成员值
double r = s.a/2;
return (3.14*r*r);
}
double InnerCircleArea3(Square &s) //引用传递
{
s.a=4;
double r = s.a/2;
return (3.14*r*r);
}
double InnerCircleArea4(const Square &s) //常引用对象传递
{
//s.a=4; 形参为常引用对象,不得修改常引用对象的成员值
double r = s.a/2;
return (3.14*r*r);
}
double InnerCircleArea5(Square *s) //指针传递
{
s->a=6;
double r = s->a/2;
return (3.14*r*r);
}
double InnerCircleArea6(const Square *s) //指向常对象的指针传递
{
//s->a=6; 形参为指向常对象的指针,不得修改常向常对象指针所指对象的成员值
double r = s->a/2;
return (3.14*r*r);
}
int main()
{
Square obj(2);
cout <<"值传递: "<< InnerCircleArea1(obj) << endl; //初始边长为2,函数内修改a为4
cout <<"常量值传递:"<< InnerCircleArea2(obj) << endl; //初始边长为2,函数内修改a为4,语法错误
cout <<"引用传递: "<< InnerCircleArea3(obj) << endl; //初始边长为2,函数内修改a为4
cout <<"常引用传递:"<< InnerCircleArea4(obj) << endl; //初始边长为2,函数内修改a为4,语法错误
cout <<"指针传递: "<< InnerCircleArea5(&obj) << endl; //初始边长为2,函数内修改a为6
cout <<"常指针传递:"<< InnerCircleArea6(&obj) << endl; //初始边长为2,函数内修改a为6,语法错误 return 0;
}

 运行结果如下

值传递:    12.56
常量值传递:3.14
引用传递: 12.56
常引用传递:12.56
指针传递: 28.26
常指针传递:28.26

运行结果

  简单总结一下,函数间传递对象有三种方式,分别是值传递、引用传递和指针传递。如果不需要修改主调函数的对象值,而只是读取其中的数据,那么程序员可以主动的将被调函数的对象形参定义成常对象、常引用或指向常对象的指针。

C++对象的应用的更多相关文章

  1. 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑

    阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...

  2. javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈

    Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...

  3. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  4. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  5. JS核心系列:浅谈原型对象和原型链

    在Javascript中,万物皆对象,但对象也有区别,大致可以分为两类,即:普通对象(Object)和函数对象(Function). 一般而言,通过new Function产生的对象是函数对象,其他对 ...

  6. Chrome出了个小bug:论如何在Chrome下劫持原生只读对象

    Chrome出了个小bug:论如何在Chrome下劫持原生只读对象 概述 众所周知,虽然JavaScript是个很灵活的语言,浏览器里很多原生的方法都可以随意覆盖或者重写,比如alert.但是为了保证 ...

  7. XStream将java对象转换为xml时,对象字段中的下划线“_”,转换后变成了两个的解决办法

            在前几天的一个项目中,由于数据库字段的命名原因 其中有两项:一项叫做"市场价格"一项叫做"商店价格" 为了便于区分,遂分别将其命名为market ...

  8. ASP.NET内置对象的总结

    1. Response对象可形象的称之为响应对象,用于将数据从服务器发送回浏览器. 实例源码:链接: http://pan.baidu.com/s/1dDCKQ8x 密码: ihq0  2. Requ ...

  9. ADO.NET对象的详解

    1. Connection 类 和数据库交互,必须连接它.连接帮助指明数据库服务器.数据库名字.用户名.密码,和连接数据库所需要的其它参数.Connection对象会被Command对象使用,这样就能 ...

  10. 对Castle Windsor的Resolve方法的解析时new对象的探讨

    依赖注入框架Castle Windsor从容器里解析一个实例时(也就是调用Resolve方法),是通过调用待解析对象的构造函数new一个对象并返回,那么问题是:它是调用哪个构造函数呢? 无参的构造函数 ...

随机推荐

  1. 面试必问的8个CSS响应式单位,你知道几个?

    大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ...

  2. PHP 运行 mkdir() Permission Denied 的原因

    使用lamp,在上传文件时,PHP执行 mkdir($path) ,  出现没有权限的错误. 解决: 本次使用的时yii框架,所以首先确保 是apache的用户对web目录有权限,然后再给此用户加 r ...

  3. MongoDB排序时内存大小限制和创建索引的注意事项!

    线上服务的MongoDB中有一个很大的表,我查询时使用了sort()根据某个字段进行排序,结果报了下面这个错误: [Error] Executor error during find command ...

  4. 如何用好Nginx的gzip指令

    说一段废话 压缩响应数据有什么作用呢?问的好:从用户体验和IT成本两方面回答这个问题: 用户体验上 网速一定的情况下,传输10MB数据比传输5MB数据的时间快了一半.所以传输数据越小用户加载页面就越快 ...

  5. Golang 实现 Redis(11): RDB 文件解析

    RDB 文件使用二进制方式存储 Redis 内存中的数据,具有体积小.加载快的优点.本文主要介绍 RDB 文件的结构和编码方式,并借此探讨二进制编解码和文件处理方式,希望对您有所帮助. 本文基于 RD ...

  6. css修改文子背景浮动

    伪元素选择器 """通过css操作文本内容""" 1.修改首个字体样式 p:first-letter{ color: blue; font- ...

  7. 原创工具14Finger-全能web指纹识别与分享平台

    14Finger 功能齐全的Web指纹扫描和分享平台,基于vue3+django前后端分离的web架构,并集成了长亭出品的rad爬虫的功能,内置了一万多条互联网开源的指纹信息. Github:http ...

  8. Kafka 万亿级消息实践之资源组流量掉零故障排查分析

    作者:vivo 互联网服务器团队-Luo Mingbo 一.Kafka 集群部署架构 为了让读者能与小编在后续的问题分析中有更好的共鸣,小编先与各位读者朋友对齐一下我们 Kafka 集群的部署架构及服 ...

  9. 第24章 Java 数据类型转换

    每日一句 井底点灯深烛伊,共郎长行莫围棋. 每日一句 What we call "failure" is not falling down, but the staying dow ...

  10. 双webview模式,子窗口打不开或者无法切换

    iOS 真机调试时,发现window.open 无效.可以结合plusReady里面不执行一起参考,博主在当时遇到这个问题只查询了资料,而后并没有来得及自己亲自验证以下方法的可行性.来日再遇上mui的 ...