静态成员变量

不能在类声明中初始化静态成员变量(声明描述了如何分配内存,但并不分配内存);

可以在类声明之外(在方法文件中)用单独的语句初始化静态成员变量;

初始化语句必须指出类型,并使用作用域解析运算符,但不使用关键字static。

C++仅允许对const整数类型的静态数据成员和枚举类型常量在类声明中初始化。

特殊成员函数

默认构造函数

默认析构函数

默认复制构造函数

何时调用:

1. 将新对象初始化为一个同类对象(显式调用复制构造函数);

1. 程序生成对象的副本时(按值传递对象或函数返回对象);

2. 编译器生成临时对象时(如:三个对象相加(连续运算)时,编译器会生成临时对象来保存中间结果)。

默认构造函数逐个赋值非静态成员(浅赋值),当成员中有指针时(由new初始化),只会复制地址,而不复制内容,当此地址被清理时,此成员所指内容将会乱码,应定义一个复制内存的复制构造函数(深度复制)

默认赋值运算符(只能由类成员函数重载)

地址运算符(隐式地址运算符返回调用对象的地址(this指针))

C++11提供了两个特殊成员函数:

移动构造函数

移动赋值运算符

字面值0可以表示空指针(C程序员经常使用NULL),C++引入了关键字nullptr来表示空指针。

静态类成员函数

可以将成员函数声明为静态的(函数声明必须包含关键字static,如果函数定义是独立的(非内联),则不能包含关键字static)。

静态函数在方法文件中的定义相似于普通成员函数。

静态函数的特点:

1. 不能通过对象调用静态成员函数(在公有部分声明的静态成员函数可以使用类名和作用域解析运算符来调用它, 此时的类名相当于命名空间);

2. 静态成员函数只能使用静态数据成员,不能访问其它数据成员。

使用new初始化对象

Class_name* pclass = new Class_name(value); //value的类型是Type_name(会调用某些构造函数)

使用new初始化的对象在调用delete时,将自动隐式地调用析构函数。

定位到自由存储区用来存储对象的定位new运算符在释放空间的时候:

必须显式地按对象创建的反向顺序使用析构函数,最后再释放缓存区
(因为delete [] 删除缓存区后,并不会主动调用缓存区中对象的析构函数)。

某些老式的编译器不支持类内嵌套结构体和类。(VS 2010不支持)

成员初始化列表

对于const数据成员,必须在执行到构造函数体之前对它进行初始化,C++使用列表初始化语法来完成此项工作。

const类成员和被声明为引用的类成员必须使用这种语法。因为引用和const数据成员一样,只能在创建时进行初始化。

这种语法只能用于构造函数。

C++11允许在类内初始化。

class Classy
{int mem1 = 10;//类内初始化const int mem2 = 20;//类内初始化    //...
};//等价于成员初始化列表
Classy::Classy() : mem1(10), mem(20)
{...
}//C++11类内初始化过的类,覆盖成员函数的默认值
Classy::Classy(int n) : mem1(n)
{...
}

禁用默认函数

将函数声明为私有的

C++11 使用关键字delete实现

类声明中数据成员的初始化(C++98)

作用域为类的普通变量(可以使用成员初始化列表)

作用域为类的静态常量(static const,允许在类声明内初始化)

作用域为类的静态变量(在方法文件中初始化)

作用域为类的枚举常量(允许在类声明内初始化)

作用域为类的const常量(必须使用成员初始化列表)

作用域为类的引用(必须使用成员初始化列表)

用链表实现队列的代码

类声明

 1 #ifndef CLASS_H_
 2 #define CLASS_H_
 3 #include<iostream>
 4 //用链表实现队列(先进先出)
 5 //注:链表的方向为从前端指向后端,最后一个节点指向空指针(0)。
 6 //插入队列为更新后端节点指针;从队列中删除为更新前端节点指针。
 7
 8 typedef double Item;//Item为项目类型的别名
 9
10 struct Node {Item item; Node* next;};//VS2010不允许类内定义结构体
11
12 class Quene
13 {
14 private:
15 //    struct Node {Item item; Node* next;};
16     Node* front;
17     Node* rear;
18     const int MAX_QUENE;
19     int items;
20 public:
21 //    Quene(Item );
22     Quene();
23     ~Quene();
24     bool enquene(Item);
25     bool dequene();
26     void show_items() const;
27 };//第二次犯错,忘写‘;’号,报构造函数的错误
28
29 #endif

方法文件

 1 #include "CLASS.h"
 2
 3 Quene::Quene() : MAX_QUENE(20)
 4 {
 5     front = 0;//起点和终点都设置为空指针
 6     rear = 0;//
 7     items = 0;
 8 }
 9
10 Quene::~Quene()
11 {
12     Node* temp;
13     int n = 0;
14     if(front != 0)
15     {
16         temp = front;
17         front = front -> next;
18         delete temp;
19     }
20 }
21
22 bool Quene::enquene(Item it)
23 {
24     if(items > MAX_QUENE)
25         return false;
26     Node* temp = new Node;
27     temp -> item = it;
28     temp -> next = 0;
29     if(front == 0)
30         front = temp;
31     else
32         rear -> next = temp;
33     rear = temp;
34     ++items;
35     return true;
36 }
37
38 bool Quene::dequene()
39 {
40
41     if(front == 0)
42         return false;
43     Node* temp = front;
44     front = front -> next;
45     --items;
46     delete temp;
47     if(items == 0)
48         rear = 0;
49     return true;
50 }
51
52 void Quene::show_items() const
53 {
54     std::cout << "have " << items << " ge!" << std::endl;
55     Node *temp;
56     temp = front;
57     std::ios_base::fmtflags orig = std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
58     while(temp != 0)
59     {
60         std::cout << temp -> item << " --> " << temp -> next << std::endl;
61         temp = temp -> next;
62     }
63     std::cout.setf(orig);
64 }

练习用的代码,总结了一些错误

头文件

 1 #ifndef a_h_
 2 #define a_h_
 3
 4 #include<string>
 5 //犯错2. 将枚举常量放在了类声明中,导致在初始化对象时出错
 6 enum sex{boy, girl};//将枚举常量放在类声明外面
 7 const int S = 10;
 8 class Person
 9 {
10 private:
11     char* name;
12     static int num_string;//静态数据成员
13     static int New;
14     sex SEX;//常量
15 public:
16     Person(char*, sex SEX = boy);//构造函数
17     Person();//默认构造函数
18     Person(Person &);//复制构造函数
19     ~Person();//析构函数
20     Person & operator=(Person &);//赋值运算符
21     Person & operator=(char*);//赋值运算符
22     void show_person();
23     void set_sex(sex);
24     static int Show_num(){return num_string;}//静态成员函数
25     static int Show_New(){return New;}
26 };//类声明之后加分号
27 //犯错3. 类声明之后的花括号后没加";"号,注:结构、枚举、类的大括号后必须加分号
28 #endif

方法文件

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include "a.h"
  4
  5 int Person::num_string = 0;//初始化静态成员
  6 int Person::New = 0;
  7 //构造函数
  8 Person::Person(char* nm, sex sx)
  9 {
 10     std::cout << S << std::endl;
 11     int len = strlen(nm);
 12     name = new char [len+1];
 13     strcpy(name, nm);//犯错1. 直接用'='赋值“name = nm”,导致调用delete时出错
 14     SEX = sx;
 15     if(sx == boy)
 16     {
 17         std::cout << "construtor! " << nm << " is a boy." << std::endl;
 18         num_string++;
 19     }
 20     else if(sx == girl)
 21     {
 22         std::cout << "construtor! " << nm << " is a girl." << std::endl;
 23         num_string++;
 24     }
 25     else
 26         std::cout << "The person is bad!!!" << std::endl;
 27 }
 28
 29
 30 //默认构造函数
 31 Person::Person()
 32 {
 33     name = new char [1];
 34     name[0] = '\0';
 35     SEX = boy;
 36     num_string++;
 37 //    std::cout << "fault constructor." << std::endl;
 38 }
 39
 40 //复制构造函数
 41 Person::Person(Person & person2)
 42 {
 43     int len = strlen(person2.name);
 44     name = new char [len+1];
 45     strcpy(name, person2.name);
 46     num_string++;
 47     std::cout << "copy constructor." << std::endl;
 48 }
 49
 50
 51 //赋值运算符重载
 52 Person & Person::operator=(Person & person3)
 53 {
 54     if(this == &person3)
 55         return *this;
 56     delete [] name;
 57     int len = strlen(person3.name);
 58     name = new char [len+1];
 59     strcpy(name, person3.name);
 60     std::cout << "object--overload operator \'=\'" << std::endl;
 61     return *this;
 62 }
 63
 64
 65 Person & Person::operator=(char* nm)
 66 {
 67     delete [] name;
 68     int len = strlen(nm);
 69     name = new char [len+1];
 70     strcpy(name, nm);
 71     std::cout << "char--overload operator \'=\'" << std::endl;
 72     New++;
 73     return *this;
 74 }
 75
 76
 77 //析构函数
 78 Person::~Person()
 79 {
 80     if(New > 0)
 81         --New;
 82     --num_string;
 83     std::cout << "destructor!!!!——" << name << std::endl;
 84     delete [] name;
 85 }
 86
 87
 88 void Person::set_sex(sex se)
 89 {
 90     SEX = se;
 91 }
 92
 93 void Person::show_person()
 94 {
 95     char se[20];
 96     if(SEX == boy)
 97         strcpy(se, "boy");
 98     else
 99         strcpy(se, "girl");
100     std::cout << name << " --> " << se << std::endl;
101 }
102
103 //int Person::Show_num()
104 //{
105 //    return num_string;
106 //}

实现文件

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<ctime>
 4 #include "a.h"
 5
 6 int main()
 7 {
 8     {
 9     //复制构造函数和赋值运算符的使用
10     Person BaiLin;
11     Person GongRen("Xiao Wang", sex(1));//将整型转换为枚举类型
12     BaiLin = GongRen;//不会调用复制构造函数//注:由于类成员name为指针,因此必须进行深度赋值(默认的赋值运算符是浅赋值,只复制地址,不复制内容)
13     Person LaoShi;
14     LaoShi = "San Mao";//犯错5.
15     }
16
17     std::cout << "***********-------***********" << std::endl;
18
19     Person *person = new Person [20];//对象数组
20     Person addper;
21     char *Name = new char [20];
22     int s;
23     int nn = 0;
24     std::cout << "type name: ";
25
26     while(nn++ < 20)
27     {
28         std::cin.get(Name, 20);
29         while(std::cin && std::cin.get() != '\n')
30             continue;
31         if(!std::cin || Name[0] == '\0')
32             break;
33         else
34             srand(time(0));//种子//time()接受一个time_t类型的地址,用于存放当前的时间(任务时),0表示空指针
35             int n = rand()%3;
36             sex SEX;
37             if( n == 0)
38                 SEX = boy;
39             else
40                 SEX = girl;
41     //        Person temp(Name, SEX);
42     //        person[nn-1] = Person(Name, SEX);//犯错4. 注:这种写法将调用析构函数(Person(Name, SEX)创建的Person对象在赋值给对象数组后自动析构)
43             person[nn-1] = Name;//更新New //犯错5. 重载了赋值运算符(object=object)后,若不定义(object=char*),就不能进行隐式的自动类型转换(char* --> Person)
44             person[nn-1].set_sex(SEX);
45             std::cout << "type name: ";
46     }
47
48     int n = Person::Show_New();
49     std::cout << "now have " << n << " person!!" << std::endl;
50
51 //    person[0].show_person();
52     while(--n >= 0)
53         person[n].show_person();
54     system("pause");
55     delete [] person;
56     return 0;
57 }

转载于:https://www.cnblogs.com/sungnox/p/7628964.html

第十二章 类和动态内存分配相关推荐

  1. 第12章类和动态内存分配

    第12章类和动态内存分配 (1) class student {char name[40];//并不是每一个字符串都是40//如果是一个对象数组,则浪费空间 }; 12.1 (1)静态成员在类声明中声 ...

  2. C++ Primer plus 第12章类和动态内存分配复习题参考答案

    假设String类有如下私有成员 class String { private:char* str; //points to string allocated by newint len; //hol ...

  3. C++ Primer Plus(第六版)第12章 类和动态内存分配

    严重性代码说明项目文件行禁止显示状态 错误    C4996    'strcpy': This function or variable may be unsafe. Consider using ...

  4. 《C++ Primer Plus》读书笔记之十—类和动态内存分配

    第12章 类和动态内存分配 1.不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存.可以在类声明之外使用单独的语句进行初始化,这是因为静态类成员是单独存储的,而不是对象的 ...

  5. C++ Primer Plus学习(十一)——类和动态内存分配

    类和动态内存分配 动态内存和类 静态类成员 特殊成员函数 string类的改进 构造函数中的new 返回对象 指向对象的指针 成员初始化列表(member initializer list) 动态内存 ...

  6. C++类与动态内存分配

    11.10 类与动态内存分配 通常,最好是在程序运行时(而不是编译时)确定诸如使用多少内存等问题.对于在对象中存储姓名来说,通常的C++方法是,在类构造函数中使用new运算符在程序运行时分配所需的内存 ...

  7. 二维数组及其动态内存分配

    一.二维数组的基本概念 1.1 二维数组的内存映像 从内存角度看,二维数组和一维数组一样,在内存中都是连续分布的多个内存单元,并没有本质差别,只是内存的管理方式不一样,如下图所示 一维数组int a[ ...

  8. 第12章-cpp类和动态内存分配

    本章内容包括: • 对类成员使用动态内存分配. • 隐式和显式复制构造函数. • 隐式和显式重载赋值运算符. • 在构造函数中使用new所必须完成的工作. • 使用静态类成员. • 将定位new运算符 ...

  9. 读书笔记||类和动态内存分配

    一.动态内存和类 C++在分配内存的时候是让程序是在运行时决定内存分配,而不是在编译时再决定.C++使用new和delete运算符来动态控制内存.但是在类中使用这些运算符将导致许多新的编程问题,在这种 ...

最新文章

  1. 宝可梦维护服务器,宝可梦大师卡在登录界面进不去,宝可梦大师为啥玩不了
  2. IDEA 每次运行项目时都提示源值1.5已过时,将在未来所有版本中删除
  3. Java script第二课
  4. Cortex‐M3-总线接口
  5. 飞蚊症手术失败与Photostress Recovery
  6. CRM Web Client UI异步搜索介绍
  7. IDEA 将 SpringBoot 项目打包成jar
  8. syslog-ng按源ip保存记录
  9. 95-190-542-源码-window-清除器(Evictors)-CountEvitor简介
  10. Leetcode 513 javascript
  11. linux 设置ssh免密登录
  12. 【资源】同济线性代数教材(第五版)
  13. C# Wke例子 -- WebUI登录窗口
  14. java 内存文件_Java内存映射文件(Memory Mapped Files)
  15. 万字干货,Podman 保姆级中文使用教程
  16. PcShare,PcClient 后门手工解决方案
  17. 数据库异常用户sa登录失败_Sa登录失败
  18. 网络原理——基础知识
  19. 什么是线速路由器 线速转发
  20. 【mongoDB】一一一一安装报错1058解决方案

热门文章

  1. 盲人也能用,优酷App做了哪些无障碍实践?
  2. 单元测试,只是测试吗?
  3. 【图解机器学习】人人都能懂的算法原理
  4. java 传入参数_Java 中方法参数的传递
  5. 华为云ModelArts完整流程引导——贴心的细致-帮你1小时完成整个训练过程
  6. 软件技术专业-就业提示(三、Java工程师必备技能)
  7. ORA-00257: archiver error. Connect internal only, until freed.
  8. 正则表达式匹配两个特殊字符中间的内容
  9. android:由URL载入中ImageView
  10. Windows 系统下Git安装图解