《C++PrimerPlus》第12章 类和动态内存分配

2023-12-23 15:30

本文主要是介绍《C++PrimerPlus》第12章 类和动态内存分配,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

12.1 动态内存和类

12.2 改进后的新String类

动态内存和类示例(编写一个String类,实现字符串的操作)

头文件string1.h

#ifndef __STRING__H__
#define __STRING__H__
#include <iostream>using namespace std;class String {
private:char *str; // 字符串的地址(字符指针)int len; // 字符串长度static int num_strings; // 创建的字符串的数量(静态变量)static const int CINLIM = 80; // 最多输入n个字符
public:String(const char *s); // 构造函数String(); // 默认构造函数String(const String &st); // 复制构造函数~String(); // 析构函数int length() const { return len; } // 返回字符串长度String &operator=(const String &st); // 重载=运算符String &operator=(const char *s); // 重载=运算符char &operator[](int i); // 重载[]运算符const char &operator[](int i) const; // 重载[]运算符friend bool operator<(const String &str1, const String &str2); // 重载<运算符friend bool operator>(const String &str1, const String &str2); // 重载>运算符friend bool operator==(const String &str1, const String &str2); // 重载==运算符friend ostream &operator<<(ostream &os, const String &st); // 运算符<<重载friend istream &operator>>(istream &is, String &st); // 运算符<<重载static int Howmany(); // 返回总共创建了几个字符串
};#endif

源代码main.cpp

#include "string1.h"
using namespace std;
const int MaxLen = 81;int main() {cout << "Hi, What's your name?" << endl;String name;cin >> name;cout << name << ", please enter a string: " << endl;String saystrings;char temp[MaxLen];cin.get(temp, MaxLen);while (cin && cin.get() != '\n') continue;saystrings = temp;cout << "Here is your sayings: " << saystrings << endl;String str = "Hello dad";if (saystrings.length() < str.length())cout << "str is longer." << endl;elsecout << "saystring is longer." << endl;if (saystrings < str)cout << "saystrings's first letter is smaller." << endl;elsecout << "str's first letter is smaller." << endl;cout << "This program used " << String::Howmany() << " objects." << endl;return 0;
}

源代码string1.cpp

#include "string1.h"
#include <cstring>// 注意不能在类声明中初始化静态成员变量
// 声明只是描述如何分配,并不分配内存
int String::num_strings = 0;int String::Howmany() {return num_strings;
}String::String(const char *s) { // StringBad str("Hello")len = strlen(s); // 获取字符串长度str = new char[len + 1]; // 开辟内存空间strcpy_s(str, len + 1, s); // 把s拷贝到strnum_strings++;
}String::String() {len = 0;str = new char[1];str[0] = '\0';num_strings++;
}String::String(const String &st) {len = st.len;str = new char[len + 1];strcpy_s(str, len + 1, st.str);num_strings++;
}String::~String() {num_strings--;delete[] str;
}String & String::operator=(const String &st) {if (this == &st) return *this; // 避免自己赋值自己(不可以有删除操作)delete[] str; // 删掉旧的数据len = st.len;str = new char[len + 1];strcpy_s(str, len + 1, st.str);return *this; // this是指针,需要取值(值为对象的引用)
}String & String::operator=(const char *s) {delete[] str;len = strlen(s);str = new char[len + 1];strcpy_s(str, len + 1, s);return *this;
}char & String::operator[](int i) {return str[i];
}const char & String::operator[](int i) const {return str[i];
}bool operator<(const String &str1, const String &str2) {return (strcmp(str1.str, str2.str) < 0);
}bool operator>(const String &str1, const String &str2) {return str2 < str1;
}bool operator==(const String &str1, const String &str2) {return (strcmp(str1.str, str2.str) == 0);
}ostream &operator<<(ostream &os, const String &st) {os << st.str;return os;
}istream &operator>>(istream &is, String &st) {char temp[String::CINLIM];is.get(temp, String::CINLIM);if (is) st = temp;while (is && is.get() != '\n') continue;return is;
}

12.3 在构造函数中使用new时的注意事项

12.4 有关返回对象的说明

12.5 使用指向对象的指针

使用new运算符示例(注意创建的地址偏移和析构函数的调用)

#include <iostream>
#include <string>
#include <new>
using namespace std;
const int BUF = 512;class JustTesting{
private:string words;int number;
public:JustTesting(const string &s = "Just Testing", int n = 0) {words = s; number = n;cout << words << " constructed\n";} // 构造函数~JustTesting() {cout << words << " destroyed\n";} // 析构函数void Show() const {cout << words << ", " << number << endl;}
};int main() {char *buffer = new char[BUF];JustTesting *pc1, *pc2;pc1 = new(buffer) JustTesting; // 定位new运算符,没有开辟空间,定位到之前开辟过的空间pc2 = new JustTesting("Heap1", 20); // 开辟了新的空间cout << "buffer: " << (void *)buffer << endl; // 打印地址cout << "heap: " << pc2 << endl;cout << pc1 << ": "; // 打印地址pc1->Show(); // 打印值cout << pc2 << ": ";pc2->Show();JustTesting *pc3, *pc4;// pc3 = new(buffer) JustTesting("Bad Idea", 6); // 极其不推荐这么做,存到同一个地方可能会数据冲突pc3 = new(buffer + sizeof(JustTesting)) JustTesting("Better Idea", 6);pc4 = new JustTesting("Heap2", 10);cout << pc3 << ": ";pc3->Show();cout << pc4 << ": ";pc4->Show();delete pc2; // 仅当显式调用delete的时候,析构函数被调用delete pc4;pc1->~JustTesting(); // 显式调用析构函数pc3->~JustTesting();delete[] buffer;return 0;
}

12.6 复习各种技术

12.7 队列模拟

设计一个队列类

头文件queue1.h

#ifndef __QUEUE_H__
#define __QUEUE_H__
#include <iostream>
using namespace std;class Customer { // 客户信息
private:long arrive; // 开始操作的时间int processtime; // 操作的总时间
public:Customer() {arrive = processtime = 0;} // 都初始化为0void set(long when); // 设置开始操作的时间long when() const { return arrive; } // 返回开始操作的时间int ptime() const { return processtime; } // 返回操作总时间
};typedef Customer Item; // Item是Customer类的对象class Queue {
private:enum { Q_SIZE = 10 };struct Node {Item item; // 存放的信息(Item表示任意类型)struct Node *next; // 指向下一个结构体的指针};Node *front; // 指向队列头的指针Node *rear; // 指向队列尾的指针int items; // 当前队列的长度(当前有多少人)const int qsize; // 队列最大值
public:Queue(int qs = Q_SIZE); // 构造函数~Queue(); // 析构函数bool isempty() const; // 判断队列是否为空bool isfull() const; // 判断队列是否为满int queuecount() const; // 返回队列长度bool enqueue(const Item &item); // 入队(返回bool表示是否成功)bool dequeue(Item &item); // 出队(返回bool表示是否成功),值存在形参中
};#endif // !__QURUE_H__

源代码main.cpp

#include "queue1.h"int main() {int qs; // 队列长度Item temp; // 创建一个Customer对象int i = 0;int customers = 0; // 有几个顾客cout << "Enter maxium size of queue: ";cin >> qs;Queue line(qs); // 创建队列while (!line.isfull()) { // 入队,直到队列为满temp.set(i++); // 填充temp的值line.enqueue(temp);customers++;}cout << "Customers: " << customers << endl;while (!line.isempty()) { // 出队,直到队列为空line.dequeue(temp);customers--;}cout << "Now, customers: " << customers << endl;return 0;
}

源代码queue1.cpp

#include "queue1.h"
#include <cstdlib>Queue::Queue(int qs) : qsize(qs) {front = rear = nullptr;items = 0;// qsize = qs; // 错误!qsize是常量,可以初始化,不可以赋值// 成员初始化列表(member Initializer list)// 只能用于构造函数,位于参数列表的右括号之后,函数体左括号之前
}Queue::~Queue() {Node *temp;while (front != nullptr) {temp = front;front = front->next;delete temp;}
}bool Queue::isempty() const {return items == 0;
}bool Queue::isfull() const {return items == qsize;
}int Queue::queuecount() const {return items;
}bool Queue::enqueue(const Item &item) {if (isfull()) return false; // 满队列直接返回falseNode *add = new Node; // 开辟新的内存空间来存储新节点add->item = item; // 值就是传递进来的参数add->next = nullptr; // 因为是末尾节点,所以指向空items++; // 队列数量+1if (front == nullptr) front = add; // 如果为空队列,则当前节点变为头节点else rear->next = add; // 否则,插入前的尾节点指向当前节点rear = add; // 当前节点变为尾节点return true;
}bool Queue::dequeue(Item &item) {if (isempty()) return false; // 空队列直接返回falseitem = front->item; // 把头结点的值赋给形参items--; // 队列数量-1Node *temp = front; // 使用临时指针存一下头结点的值front = front->next; // 调整头结点为下一个值delete temp; // 释放临时指针所指向的内存空间if (items == 0) rear = nullptr; // 如果为空队列,则尾节点变为空return true;
}void Customer::set(long when) {arrive = when; // 记录开始操作的时间processtime = rand() % 3 + 1; // 随机出一个1~3分钟的总操作时长
}

这篇关于《C++PrimerPlus》第12章 类和动态内存分配的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/528527

相关文章

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

详解C++中类的大小决定因数

《详解C++中类的大小决定因数》类的大小受多个因素影响,主要包括成员变量、对齐方式、继承关系、虚函数表等,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 非静态数据成员示例:2. 数据对齐(Padding)示例:3. 虚函数(vtable 指针)示例:4. 继承普通继承虚继承5.