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

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

程序示例分析:

(1)

#include<iostream>
using namespace std;
class Demo {
int id;
public:
Demo(int i) { //类型构造函数
id = i;
cout << "id=" << id << " constructed" << endl;
}
~Demo() { //析构函数
cout << "id=" << id << " destructed" << endl;
}
};
Demo d1(); //全局变量,在main之前初始化
void Func()
{
static Demo d2();//静态局部变量,func结束消亡
Demo d3();
cout << "func" << endl;
}
int main() {
Demo d4();
d4 = ;
cout << "main" << endl;
{ Demo d5(); //局部变量的作用域和生存期都只到离它最近的,且将其包含在内的那一对“{}”中的“}”为止
}
Func(); //引发析构函数
cout << "main ends" << endl;
return ;
}

输出结果:

id= constructed
id= constructed
id= constructed
id= destructed
main
id= constructed
id= destructed
id= constructed
id= constructed
func
id= destructed
main ends
id= destructed
id= destructed
id= destructed

(2)

#include <iostream>
using namespace std;
class CMyclass {
public:
CMyclass() {};
CMyclass( CMyclass & c)
{
cout << "copy constructor" << endl;
}
~CMyclass() { cout << "destructor" << endl; }
};

输出结果:

copy constructor
fun
destructor //参数消亡
test
copy constructor
destructor // 返回值临时对象消亡
destructor // 局部变量消亡
destructor // 全局变量消亡

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

class A {
public:
int x;
A(int x_):x(x_)
{ cout << x << " constructor called" << endl; }
A(const A & a ) { //本例中dev需要此const其他编译器不要
x = + a.x;
cout << "copy called" << endl;
}
~A() { cout << x << " destructor called" << endl; }
};
A f( ){ A b(); return b; }
int main( ){
A a();
a = f();
return ;
}

Visual Studio输出结果:

 constructor called
constructor called
copy called
destructor called
destructor called
destructor called

Dev C++输出结果:

 constructor called
constructor called
destructor called
destructor called

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

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

(1)概念

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

class CRectangle
{
private:
int w, h;
static int nTotalArea; //静态成员变量
static int nTotalNumber; //静态成员变量
public:
CRectangle(int w_, int h_);
~CRectangle();
static void PrintTotal(); //静态成员函数
};

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

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

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

class CMyclass {
int n;
static int s;
};

sizeof( CMyclass ) 等于 4

(2)如何访问静态成员

①类名::成员名

CRectangle::PrintTotal();

②对象名.成员名

CRectangle r;
r.PrintTotal();

③指针->成员名

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

④引用.成员名

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

(3)静态成员示例

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

#include<iostream>
using namespace std;
class CRectangle
{
private:
int w, h;
static int nTotalArea;
static int nTotalNumber;
public:
CRectangle(int w_, int h_);
~CRectangle();
static void PrintTotal();
};
CRectangle::CRectangle(int w_, int h_)
{
w = w_;
h = h_;
nTotalNumber++;
nTotalArea += w * h;
}
CRectangle::~CRectangle()
{
nTotalNumber--;
nTotalArea -= w * h;
}
void CRectangle::PrintTotal()
{
cout << nTotalNumber << "," << nTotalArea << endl;
}
int CRectangle::nTotalNumber = ;
int CRectangle::nTotalArea = ;
// 必须在定义类的文件中对静态成员变量进行一次说明
//或初始化。否则编译能通过,链接不能通过。
int main()
{
CRectangle r1(, ), r2(, );
//cout << CRectangle::nTotalNumber; // Wrong , 私有
CRectangle::PrintTotal();
r1.PrintTotal();
return ;
}

输出结果:

,
,

此CRectangle类写法, 有何缺陷?

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

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

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

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

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

CRectangle :: CRectangle(CRectangle & r )
{
w = r.w; h = r.h;
nTotalNumber ++;
nTotalArea += w * h;
}

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

void CRectangle::PrintTotal()
{
cout << w << "," << nTotalNumber << "," <<nTotalArea << endl; //wrong
}
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. 列举mvc ActionResult的返回值

    8.列举ASP.NET MVC ActionResult的返回值有几种类型? 主要有View(视图).PartialView(部分视图).Content(内容).Json(Json字符串).Javas ...

  2. 五 Mybatis一对一关联查询的两种方式(基于resultType&基于resultMap)

    关联查询: 一个用户对应多个订单,一个订单只有一个用户 订单关联用户:两种方式 一:基于resultTYpe,一个与表关系一样的pojo实现 主表订单,从表用户 首先要有一个与关联查询表关系一样的po ...

  3. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 辅助类:设置元素为 display:block 并居中显示

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

  4. http-equiv属性的属性值X-UA-Compatible

    参考:https://blog.csdn.net/changjiangbuxi/article/details/26054755

  5. 高斯消元几道入门题总结POJ1222&&POJ1681&&POJ1830&&POJ2065&&POJ3185

    最近在搞高斯消元,反正这些题要么是我击败了它们,要么就是这些题把我给击败了.现在高斯消元专题部分还有很多题,先把几道很简单的入门题总结一下吧. 专题:http://acm.hust.edu.cn/vj ...

  6. 第1节 kafka消息队列:2、kafka的架构介绍以及基本组件模型介绍

    3.kafka的架构模型 1.producer:消息的生产者,主要是用于生产消息的.主要是接入一些外部的数据源,从外部获取数据,比如说我们可以从flume获取数据,还可以通过ftp传入数据等,还可以通 ...

  7. VueCli3 项目结构和具体作用

  8. 超大数据量操作 java程序优化[转载]

        一个表中有1000万以上的数据,要对其进行10万次以上的增删查改的操作,请问如何优化java程序对数据库的操作? 通过使用一些辅助性工具来找到程序中的瓶颈,然后就可以对瓶颈部分的代码进行优化. ...

  9. Django博客开发-数据建模与样式设定

    开发流程介绍 之前Django的学习过程当中已经把基本Django开发学完了,现在以Django 的博客项目完成一遍课程的回顾和总结.同时来一次完整开发的Django体验. 一个产品从研究到编码我们要 ...

  10. 2018--Linux命令总结整理复习版

    一.ls命令: 用来显示目标列表,在Linux中是使用率较高的命令.ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件. -a:显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为影 ...