c++中构造函数 、析构函数的作用域详解

  我们知道,在c++中,析构函数是在函数作用域尾部执行析构函数,从而释放对象,但是有一种情况下,析构函数作用域发生变化,请看下面的例子,定义了一个Stock类,Stock类存放在stock.h中,主调用函数在stock.cpp中。

  stock.h  

  1 #include <iostream>
  2 #include <string.h>
  3 class Stock{
  4 private:
  5    char m_company[30];
  6    int m_stock_num;
  7    float m_stock_price;
  8    float total_price;
  9    float stock_sum(){total_price= m_stock_num*m_stock_price;}
 10
 11 public:
 12    int get_stock(char *company,int stock_num,float stock_price);
 13    void increase(int num,float price);
 14    void sell(int num,float price);
 15    void update_price(float price);
 16    void print_stock_info();
 17    friend Stock plus1(int stock_num,Stock t);
 18    Stock operator+(Stock t);
 19    Stock(char *p,int num,float price);
 20    Stock();
 21    ~Stock();
 22 };
 23
 24 Stock::Stock(char *company,int stock_num,float stock_price)
 25 {
 26    int len=strlen(company);
 27    strncpy(m_company,company,len+1);
 28    m_stock_num=stock_num;
 29    m_stock_price=stock_price;
 30    stock_sum();
 31
 32 }
 33
 34 Stock::Stock()
 35 {
 36    m_stock_num=0;
 37    m_stock_price=0;
 38    stock_sum();
 39    std::cout<<"hello boy"<<std::endl;
 40 }
 41
 42 Stock::~Stock()
 43 {
 44    std::cout<<"good bye"<<std::endl;
 45
 46 }
 47
 48 Stock plus1(int stock_num,Stock t)
 49 {
 50    Stock total;
 51    total.m_stock_num=stock_num+t.m_stock_num;
 52    return total;
 53
 54 }
 55
 56
 57 inline Stock Stock::operator+(Stock t)
 58 {
 59    Stock total;
 60    total.m_stock_num=m_stock_num+t.m_stock_num;
 61    total.total_price=total_price+t.total_price;
 62    return total;
 63 }
 64
 65 inline int Stock::get_stock(char * company,int stock_num,float stock_price)
 66 {
 67    int len=strlen(company);
 68    if (len>30)
 69       return false;
 70    strncpy(m_company,company,len+1);
 71    m_stock_num=stock_num;
 72    m_stock_price=stock_price;
 73    stock_sum();
 74    return true;
 75 }
 76
 77 void Stock::increase(int num,float price)
 78 {
 79    m_stock_num=m_stock_num+num;
 80    m_stock_price=price;
 81    stock_sum();
 82 }
 83
 84 void Stock::sell(int num,float price)
 85 {
 86    if(num>m_stock_num)
 87       m_stock_num=0;
 88    else
 89       m_stock_num=m_stock_num-num;
 90
 91    m_stock_price=price;
 92    stock_sum();
 93 }
 94 void Stock::update_price(float price)
 95 {
 96    m_stock_price=price;
 97
 98 }
 99 void Stock::print_stock_info()
100 {
101    std::cout<<m_stock_num<<std::endl;
102    std::cout<<total_price<<std::endl;
103 }

  stock.cpp  

 1 #include "stock.h"
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 int main()
 6  {
 7    char *p;
 8    p=new char[100];
 9    strcpy(p,"baidu");
10    Stock object[4];
11    object[0].get_stock(p,100,2.3);
12    object[1].get_stock(p,100,2.3);
13    object[2]=object[0]+object[1];
14    object[2].print_stock_info();
15    object[3]=plus1(100,object[2]);
16    object[3].print_stock_info();
17    return true;
18
19  }

  可以看到我们声明友元函数plus1后,将object[2]对象通过构造函数传递到友元中,此时友元函数中先调用拷贝构造函数接受参数,然后调用 默认构造函数形成局部total对象,在我们完成加的动作之后,对象要返回,此时调用析构函数,但若此时我们采用引用的返回值方式 Stock &plus1(int stock_num,Stock t) ,调用同样成功,但对象被销毁了,为什么还可以被引用  而继续使用。我们来看一下两种返回方式的结果:

  返回对象,

返回对象引用,

  此时编译器应该是做过优化,因为函数的作用域结尾处,应该调用过析构函数了(从图中可以看出来,调用了5次构造函数,6次析构函数,有一次复制构造函数),所以析构 函数肯定是被执行了,但是编译器作过优化处理,使得对象依旧可以被传递,此时编译器会给出警告提示。但是在1个函数中,我们可以返回1个在函数调用结束不会被释放的对象的引用。比如外部传入的对象,比如函数所属类的成员变量等。而返回局部变量(对象引用)是很危险的,但是返回对象则是可以的,因为返因对象时会调用复制构造函数、然后才是析构函数。如果我们plus1调用传递的是引用时,此时结果为

,不会调用复制构造函数。当改为值传递后,复制构造函数又被重新调用,

时间: 2024-10-14 17:06:43

c++中构造函数 、析构函数的作用域详解的相关文章

【转】 c++拷贝构造函数(深拷贝,浅拷贝)详解

c++拷贝构造函数(深拷贝,浅拷贝)详解 2013-11-05 20:30:29 分类: C/C++ 原文地址:http://blog.chinaunix.net/uid-28977986-id-3977861.html 一.什么是拷贝构造函数      首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=100; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.  下面看一个类对象拷贝的简单例子. #include<iostream

JDK中的Timer和TimerTask详解

目录结构: Timer和TimerTask 一个Timer调度的例子 如何终止Timer线程 关于cancle方式终止线程 反复执行一个任务 schedule VS. scheduleAtFixedRate 一些注意点 1. Timer和TimerTask Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次. TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务. 2.

struts2中&lt;s:checkboxlist/&gt;的用法详解

Html代码 选择角色<br> <s:checkboxlist list="#request.roleuserList" listKey="roleId" listValue="roleName" value="#request.rolelist.{roleId}" name="roleIds"></s:checkboxlist> 说明: 其中#request.roleu

C#中的IDisposable模式用法详解

本文实例讲述了C#中IDisposable模式的用法,针对垃圾资源的回收进行了较为详细的讲解.分享给大家供大家参考之用.具体方法如下: 首先,对于垃圾回收而言,在C#中,托管资源的垃圾回收是通过CLR的Garbage Collection来实现的,Garbage Collection会调用堆栈上对象的析构函数完成对象的释放工作:而对于一些非托管资源,比如数据库链接对象等,需要实现IDisposable接口进行手动的垃圾回收.那么什么时候使用Idisposable接口,以及如何使用呢? 先来参考一

Java中InvocationHandler接口中第一个参数proxy详解

java动态代理机制中有两个重要的类和接口InvocationHandler(接口)和Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心: 1.InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序:在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法. 看下官方文档对InvocationHandler接口的描述: {@code Invocat

oc中字典的实现方法详解

一:字典的基本概念 Foundation中的字典(NSDictionary,NSMutableDictionary)是由键-值对组成的数据集合.正如,我们在字典里查找单词的定义一样. 通过key(键),查找的对应的value(值),key通常是字符串对象,也可以是其他任意类型对象.在一个字典对象中,key的值必须是唯一的. 此外,字典对象的键和值不可以为空(nil),如果需要在字典中加入一个空值,可以加入NSNull对象 二:不可变字典-NSDictionary 1:初始化(以一个元素和多个元素

Android总结篇系列:Activity中几个主要函数详解

专注Android领域开发. 仰望星空,同时需要脚踏实地. ——好记性不如烂博客 Android总结篇系列:Activity中几个主要函数详解 Activity作为Android系统中四大基本组件之一,包含大量的与其他的各大组件.intent.widget以及系统各项服务等之间的交互的函数.在此,本文主要选取实际项目开发中常用的,但完全理解又需要有一定深入了解的几个函数进行讲解,后续本文会根据需要不断更新. 1. startActivityForResult / onActivityResult

【转载】lucene中Field.Index,Field.Store详解

lucene在doc.add(new Field("content",curArt.getContent(),Field.Store.NO,Field.Index.TOKENIZED)); Field有两个属性可选:存储和索引. 通过存储属性你可以控制是否对这个Field进行存储: 通过索引属性你可以控制是否对该Field进行索引. 事实上对这两个属性的正确组合很重要. Field.Index Field.Store 说明 TOKENIZED(分词) YES 被分词索引且存储 TOKE

【Unity编程】Unity中关于四元数的API详解

Unity中关于四元数的API详解 Quaternion类 Quaternion(四元数)用于计算Unity旋转.它们计算紧凑高效,不受万向节锁的困扰,并且可以很方便快速地进行球面插值. Unity内部使用四元数来表示所有的旋转. Quaternion是基于复数,并不容易直观地理解. 不过你几乎不需要访问或修改单个四元数参数(x,y,z,w); 大多数情况下,你只需要获取和使用现有的旋转(例如来自"Transform"),或者用四元数来构造新的旋转(例如,在两次旋转之间平滑插入). 大