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

一、对象数组

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. javaScript中Number数字类型方法入门

    前言 Number和Math都属于JavaScript中的内置对象,Number数字类型作为基础数据类型,我们在开发过程中会经常用到,包括数字精度的格式化,还有字符串转换成数字等操作. Number数 ...

  2. ucore lab7 同步互斥机制 学习笔记

    管程的设计实在是精妙,初看的时候觉得非常奇怪,这混乱的进程切换怎么能保证同一时刻只有一个进程访问管程?理清之后大为赞叹,函数中途把前一个进程唤醒后立刻把自己挂起,完美切换.后一个进程又在巧妙的时机将自 ...

  3. Keepalived入门学习

    一个执着于技术的公众号 Keepalived简介 Keepalived 是使用C语言编写的路由热备软件,该项目软件起初是专门为LVS负载均衡设计的,用来管理并监控LVS集群系统中各个服务节点的状态,后 ...

  4. OpenStack平台镜像优化

    在使用打快照方式制作镜像后,镜像的大小会变得非常大,比如一个基础的CentOS镜像大小为400M左右,但是使用打快照方式制作的镜像大小会有1个G左右,具体的大小还要根据安装的东西来实际情况实际分析. ...

  5. 解构HE2E中的Kubernetes技术应用

    摘要:我们从Kubernetes技术应用的角度解构华为云DevCloud HE2E DevOps实践. 本文分享自华为云社区<解构HE2E中的Kubernetes技术应用>,作者: 敏捷小 ...

  6. HDFS High Availability(HA)高可用配置

    高可用性(英语:high availability,缩写为 HA) IT术语,指系统无中断地执行其功能的能力,代表系统的可用性程度.是进行系统设计时的准则之一. 高可用性系统意味着系统服务可以更长时间 ...

  7. 使用 awk 命令统计文本

    2022-04-19 11:25:15.008,b4d13bfca8fe4b93a85e65a88520d945,LogScheduler#printLog,10ms,Y,xxxxxxxx 2022- ...

  8. 5分钟快速搭建一个springboot的项目

      现在开发中90%的人都在使用springboot进行开发,你有没有这样的苦恼,如果让你新建一个springboot开发环境的项目,总是很苦恼,需要花费很长时间去调试.今天来分享下如何快速搭建. 一 ...

  9. SpringBoot 整合 RabbitMQ 实现消息可靠传输

    消息的可靠传输是面试必问的问题之一,保证消息的可靠传输主要在生产端开启 comfirm 模式,RabbitMQ 开启持久化,消费端关闭自动 ack 模式. 环境配置 SpringBoot 整合 Rab ...

  10. C++primer第二章

    第二章 :变量和基本类型 2.1 基本内置类型 C++定义了一套包含算术类型(arithmetic type)和空类型(void)在内的基本数据类型 2.1.1 算术类型 算术类型的分类: 整型(in ...