1、构造函数、析构函数和变量的生存期

构造函数在对象生成时会被调用,析构函数在对象消亡时会被调用。

程序示例分析:

(1)

  1. #include<iostream>
  2. using namespace std;
  3. class Demo {
  4. int id;
  5. public:
  6. Demo(int i) { //类型构造函数
  7. id = i;
  8. cout << "id=" << id << " constructed" << endl;
  9. }
  10. ~Demo() { //析构函数
  11. cout << "id=" << id << " destructed" << endl;
  12. }
  13. };
  14. Demo d1(); //全局变量,在main之前初始化
  15. void Func()
  16. {
  17. static Demo d2();//静态局部变量,func结束消亡
  18. Demo d3();
  19. cout << "func" << endl;
  20. }
  21. int main() {
  22. Demo d4();
  23. d4 = ;
  24. cout << "main" << endl;
  25. { Demo d5(); //局部变量的作用域和生存期都只到离它最近的,且将其包含在内的那一对“{}”中的“}”为止
  26. }
  27. Func(); //引发析构函数
  28. cout << "main ends" << endl;
  29. return ;
  30. }

输出结果:

  1. id= constructed
  2. id= constructed
  3. id= constructed
  4. id= destructed
  5. main
  6. id= constructed
  7. id= destructed
  8. id= constructed
  9. id= constructed
  10. func
  11. id= destructed
  12. main ends
  13. id= destructed
  14. id= destructed
  15. id= destructed

(2)

  1. #include <iostream>
  2. using namespace std;
  3. class CMyclass {
  4. public:
  5. CMyclass() {};
  6. CMyclass( CMyclass & c)
  7. {
  8. cout << "copy constructor" << endl;
  9. }
  10. ~CMyclass() { cout << "destructor" << endl; }
  11. };

输出结果:

  1. copy constructor
  2. fun
  3. destructor //参数消亡
  4. test
  5. copy constructor
  6. destructor // 返回值临时对象消亡
  7. destructor // 局部变量消亡
  8. destructor // 全局变量消亡

2、复制构造函数在不同编译器中的表现

  1. class A {
  2. public:
  3. int x;
  4. A(int x_):x(x_)
  5. { cout << x << " constructor called" << endl; }
  6. A(const A & a ) { //本例中dev需要此const其他编译器不要
  7. x = + a.x;
  8. cout << "copy called" << endl;
  9. }
  10. ~A() { cout << x << " destructor called" << endl; }
  11. };
  12. A f( ){ A b(); return b; }
  13. int main( ){
  14. A a();
  15. a = f();
  16. return ;
  17. }

Visual Studio输出结果:

  1. constructor called
  2. constructor called
  3. copy called
  4. destructor called
  5. destructor called
  6. destructor called

Dev C++输出结果:

  1. constructor called
  2. constructor called
  3. destructor called
  4. destructor called

说明Dev出于优化目的并未生成返回值临时对象。 VS无此问题

3、静态成员变量和静态成员函数

(1)概念

静态成员:在说明前面加了static关键字的成员。

  1. class CRectangle
  2. {
  3. private:
  4. int w, h;
  5. static int nTotalArea; //静态成员变量
  6. static int nTotalNumber; //静态成员变量
  7. public:
  8. CRectangle(int w_, int h_);
  9. ~CRectangle();
  10. static void PrintTotal(); //静态成员函数
  11. };

普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。因此静态成员不需要通过对象就能访问。

静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在。静态成员函数本质上是全局函数。设置静态成员这种机制的目的是将和某些类紧密相关的全局变 量和函数写到类里面,看上去像一个整体,易于维护和理解。

sizeof 运算符不会计算静态成员变量。

  1. class CMyclass {
  2. int n;
  3. static int s;
  4. };

sizeof( CMyclass ) 等于 4

(2)如何访问静态成员

①类名::成员名

  1. CRectangle::PrintTotal();

②对象名.成员名

  1. CRectangle r;
  2. r.PrintTotal();

③指针->成员名

  1. CRectangle * p = &r;
  2. p->PrintTotal();

④引用.成员名

  1. CRectangle & ref = r;
  2. int n = ref.nTotalNumber;

(3)静态成员示例

考虑一个需要随时知道矩形总数和总面积的图形处理程序可以用全局变量来记录总数和总面积用静态成员将这两个变量封装进类中,就更容易理解和维护

  1. #include<iostream>
  2. using namespace std;
  3. class CRectangle
  4. {
  5. private:
  6. int w, h;
  7. static int nTotalArea;
  8. static int nTotalNumber;
  9. public:
  10. CRectangle(int w_, int h_);
  11. ~CRectangle();
  12. static void PrintTotal();
  13. };
  14. CRectangle::CRectangle(int w_, int h_)
  15. {
  16. w = w_;
  17. h = h_;
  18. nTotalNumber++;
  19. nTotalArea += w * h;
  20. }
  21. CRectangle::~CRectangle()
  22. {
  23. nTotalNumber--;
  24. nTotalArea -= w * h;
  25. }
  26. void CRectangle::PrintTotal()
  27. {
  28. cout << nTotalNumber << "," << nTotalArea << endl;
  29. }
  30. int CRectangle::nTotalNumber = ;
  31. int CRectangle::nTotalArea = ;
  32. // 必须在定义类的文件中对静态成员变量进行一次说明
  33. //或初始化。否则编译能通过,链接不能通过。
  34. int main()
  35. {
  36. CRectangle r1(, ), r2(, );
  37. //cout << CRectangle::nTotalNumber; // Wrong , 私有
  38. CRectangle::PrintTotal();
  39. r1.PrintTotal();
  40. return ;
  41. }

输出结果:

  1. ,
  2. ,

此CRectangle类写法, 有何缺陷?

在使用CRectangle类时,有时会调用复制构造函数生成临时的隐藏的CRectangle对象

调用一个以CRectangle类对象作为参数的函数时

调用一个以CRectangle类对象作为返回值的函数时

临时对象在消亡时会调用析构函数,减少nTotalNumber 和 nTotalArea的值,可是这些临时对象在生成时却没有增加 nTotalNumber 和 nTotalArea的值。

解决办法:为CRectangle类写一个复制构造函数。

  1. CRectangle :: CRectangle(CRectangle & r )
  2. {
  3. w = r.w; h = r.h;
  4. nTotalNumber ++;
  5. nTotalArea += w * h;
  6. }

(4)为什么在静态成员函数中,不能访问非静态成员变量, 也不能调用非静态成员函数?

  1. void CRectangle::PrintTotal()
  2. {
  3. cout << w << "," << nTotalNumber << "," <<nTotalArea << endl; //wrong
  4. }
  5. CRetangle::PrintTotal(); //解释不通,w 到底是属于那个对象的?

《新标准C++程序设计》3.3-3.4(C++学习笔记7)的更多相关文章

  1. 《新标准C++程序设计》4.5(C++学习笔记15)

    实例:长度可变的整型数组类 int main() { //要编写可变长整型数组类,使之能如下使用: CArray a; //开始里的数组是空的 ; i < ; ++i) a.push_back( ...

  2. 《新标准C++程序设计》4.6(C++学习笔记16)

    重载流插入运算符和流提取运算符 流插入运算符:“<<” 流提取运算符:“>>” cout 是在 iostream 中定义的,ostream 类的对象. “<<” 能 ...

  3. 《新标准C++程序设计》4.4(C++学习笔记14)

    运算符重载为友元函数 一般情况下,将运算符重载为类的成员函数,是较好的选择. 但有时,重载为成员函数不能满足使用要求,重载为普通函数,又不能访问类的私有成员,所以需要将运算符重载为友元. class ...

  4. 《新标准C++程序设计》4.1(C++学习笔记12)

    运算符重载的概念和原理 一.运算符重载的需求 C++预定义的“+.-. * ./.%. ^ .&.~.!.|. = .<< >>.!= ”等运算符,只能用于基本数据类型 ...

  5. 《新标准C++程序设计》3.8(C++学习笔记10)

    友元 友元分为友元函数和友元类两种. 一.友元函数 在定义一个类的时候,可以把一些函数(包括全局函数和其它类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对 ...

  6. 《新标准C++程序设计》3.5(C++学习笔记8)

    常量对象和常量成员函数 一.常量对象 如果希望某个对象的值初始化后就再也不被改变,则定义该对象时可以在前面加const关键字,使之成为常量对象. class CDemo { private: int ...

  7. 正确处理类的复合关系------新标准c++程序设计

    假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是 ...

  8. 在成员函数中调用虚函数(关于多态的注意事项)------新标准c++程序设计

    类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespa ...

  9. 多态实现的原理------新标准c++程序设计

    “多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定.例子: #include<iostream> using namespac ...

  10. 多态的作用-游戏编程展示------新标准c++程序设计

    游戏软件的开发最能体现面向对象设计方法的优势.游戏中的人物.道具.建筑物.场景等都是很直观的对象,游戏运行的过程就是这些对象相互作用的过程.每个对象都有自己的属性和方法,不同对象也可能有共同的属性和方 ...

随机推荐

  1. Hive的存储和MapReduce处理——数据清洗(Part2)

    日期:2019.11.14 博客期:116 星期四 基本的处理类 import java.sql.Connection; import java.sql.DriverManager; import j ...

  2. 中山Day10——普及

    今天又是愚蠢的一天,估分230,实得110.其中T2.4不会,这里就只说题意和简要思路. 收获:scanf>>a,以及printf<<a. T1:模板题 此题相对简单,就是读入 ...

  3. smoj2806建筑物

    题面 有R红色立方体,G绿色立方体和B蓝色立方体.每个立方体的边长是1.现在有一个N × N的木板,该板被划分成1×1个单元.现在要把所有的R+G+B个立方体都放在木板上.立方体必须放置在单元格内,单 ...

  4. sigprocmask

    sigprocmask 检测和更改进程的信号屏蔽字 初始化信号屏蔽字的函数 sigprocempty--设置空的信号屏蔽字 sigprocfillset----设置全集的信号屏蔽字

  5. 初识Prometheus

    安装Prometheus Server Prometheus基于Golang编写,编译后的软件包,不依赖于任何的第三方依赖.用户只需要下载对应平台的二进制包,解压并且添加基本的配置即可正常启动Prom ...

  6. 十二、js去掉空格_比较字符长度_中英文判断_页面初始化_简体字与繁字体判断

    1.去掉字符串前后所有空格 function trimBlank(str){ return str.replace(/(^\s*)|(\s*$)/g, ""); } 2.字符串长度 ...

  7. PHP+swoole实现聊天群发功能

    本篇文章主要介绍PHP+swoole实现聊天群发功能,感兴趣的朋友参考下,希望对大家有所帮助. php代码: $serv = new swoole_websocket_server("127 ...

  8. 谈一下你对uWSGI和 nginx的理解(原理)

    要注意 WSGI / uwsgi / uWSGI 这三个概念的区分. WSGI是一种通信协议. uwsgi是一种线路协议而不是通信协议,在此常用于在uWSGI服务器与其他网络服务器的数据通信. uWS ...

  9. vDom和domDiff

    虚拟dom和domDiff 1. 构建虚拟DOM var tree = el('div', {'id': 'container'}, [ el('h1', {style: 'color: blue'} ...

  10. 《Netlogo多主体建模入门》笔记8

    8 -GINI系数计算与 如何使用行为空间做实验     首先,我们加入保底机制. 对于每一个agent,都有一个随机的保底比例 s(每个agent的 s 不都一样,且s初始化之后不会改变) 进行交易 ...