《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++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

2024/9/8 c++ smart

1.通过自己编写的class来实现unique_ptr指针的功能 #include <iostream> using namespace std; template<class T> class unique_ptr { public:         //无参构造函数         unique_ptr();         //有参构造函数         unique_ptr(