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

一、对象数组

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. 漏洞复现:MS12-020 远程桌面协议RDP远程代码执行漏洞

    漏洞复现:MS12-020 远程桌面协议RDP远程代码执行漏洞 攻击机:Kali2019 靶机:Win7 64位 解题步骤: 1.打开Kali2019和Win7 64位 ,确定IP地址是多少 2.确定 ...

  2. 软件包管理-yum私有仓库

    Linux软件安装 包的依赖关系: 软件包之间可能存在依赖关系,甚至循环依赖,即:A包依赖B包,B包依赖C包,C包依赖A包 安装软件包时,会因为缺少依赖的包,而导致安装包失败. 解决依赖包管理工具: ...

  3. 1.16 Linux该如何学习(新手入门必看)

    本节旨在介绍对于初学者如何学习 Linux 的建议.如果你已经确定对 Linux 产生了兴趣,那么接下来我们介绍一下学习 Linux 的方法. 如何去学习 学习大多类似庖丁解牛,对事物的认识一般都是由 ...

  4. linux fedora35 配置jdk,安装mysql,安装tomcat

    配置jdk18很简单,下载jdk,只需要.tar.gz结尾的文件就行,https://download.oracle.com/java/18/latest/jdk-18_linux-x64_bin.t ...

  5. NMS技术总结(NMS原理、多类别NMS、NMS的缺陷、NMS的改进思路、各种NMS方法)

    ​  前言  本文介绍了NMS的应用场合.基本原理.多类别NMS方法和实践代码.NMS的缺陷和改进思路.介绍了改进NMS的几种常用方法.提供了其它不常用的方法的链接. 本文很早以前发过,有个读者评论说 ...

  6. Tomcat配置安装

    1.tomcat是什么? 是由JAVA开发的开源且免费,主要是用于web服务器,是中间件.主要用于中小型企业 2.tomcat安装 安装jdk,可以rpm或者官网安装,安装完配置java环境变量,打开 ...

  7. python 批量探测服务端开放的TCP端口

    现在大多服务器都有做icmp限制或直接禁掉,导致我们业务去连接服务器异常时无法判断是程序问题还是网络问题,所以写一个简单探测tcp端口脚本来探测服务器所开放的端口,再使用tcp测试双向时延来排掉网络问 ...

  8. Java注解Annotaton

    1.三种基本的Annotaton @Override : 限定某个方法,是重写父类方法 , 该注解只能用于方法 @Deprecated : 用于表示某个程序元素 ( 类 , 方法等 ) 已过时 @Su ...

  9. 渗透:aircrack-ng

    ircrack- NG是一个完整的工具来评估Wi-Fi网络安全套件,功能包括: 监控:数据包捕获和导出数据到文本文件,以供第三方工具进一步处理. 攻击:通过数据包注入回放攻击,去认证,伪造接入点等. ...

  10. async用法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...