衡水做淘宝网站,广告创意与设计,qq旧版本大全官方下载,wordpress改地址目录 一、复习题二、编程练习 一、复习题
1. 假设String类有如下私有成员#xff1a;
// String 类声明
class String
{
private: char* str;int len;// ...
};a. 下述默认构造函数有什么问题#xff1f;
String::String() { } // 默认构造函数b. 下述构造函数有什么问题… 目录 一、复习题二、编程练习 一、复习题
1. 假设String类有如下私有成员
// String 类声明
class String
{
private: char* str;int len;// ...
};a. 下述默认构造函数有什么问题
String::String() { } // 默认构造函数b. 下述构造函数有什么问题
String::String(const char* s) // 构造函数
{str s;len strlen;
}c. 下述构造函数有什么问题
String::String(const char* s) // 构造函数
{strcpy(str, s);len strlen(s);
}答注意下面的代码需要包含相应的头文件和using声明。 a. 该默认函数并未进行任何操作则成员变量str与len的值是未知的和创建局部变量未初始化一个道理。而String类涉及动态内存分配所以需要给str适当初始化一般初始化为空指针——nullptr。 修改如下
String::String() // 默认构造函数
{str nullptr;len 0
}b. 该构造函数中语句str s; 只是单纯地让str和s指向同一个字符串str只是存储了s指向的字符串的首地址这是浅拷贝。而我们需要拷贝存储字符串的副本深拷贝。 修改如下
String::String(const char* s)
{len strlen(s); // 存储字符串的长度不包括空字符str new char[len 1]; // 申请空间别忘了空字符\0strcpy(str, s); // 拷贝字符串内容副本
}c. 还未在堆上申请空间str指向的地方是未知的直接使用函数strcpy()进行内容拷贝会导致不确定的问题。 修改如下
String::String(const char* s)
{len strlen(s); // 存储字符串的长度不包括空字符str new char[len 1]; // 申请空间别忘了空字符\0strcpy(str, s); // 拷贝字符串内容副本
}2. 如果你定义了一个类其指针成员是使用new初始化的请指出可能出现的三个问题及如何纠正这些问题
答 1问题没有定义对应的析构函数和使用对应的delete运算符的形式。 纠正使用new为成员指针分配空间需要对应的析构函数来释放空间使用什么形式申请空间就需要使用什么形式释放空间如int * pi new int; —— delete pi; int* pa new int[5];——delete[5]pa;。而且所有构造函数只能使用上面相同的一种new形式使之与析构函数中的delete形式对应。 2问题没有定义相关的复制构造函数。 纠正如果没有定义赋值构造函数编译器会提供默认的复制构造函数其只能进行浅拷贝只能复制需要拷贝的内容的地址。需要定义相关的复制构造函数进行深拷贝为拷贝内容申请空间。 3问题没有重载对应的赋值运算符 纠正和问题2一样如果没有重载赋值运算符编译器也会提供默认的同样是浅拷贝。我们需要定义相关的赋值运算符来进行深度拷贝。需要先释放前面存储的动态空间然后根据拷贝大小申请新的空间。
3. 如果没有显示提供类方法编译器将自动生成哪些类方法请描述这些隐式生成的函数的行为。
答 1若没有提供构造函数则编译器会提供一个默认构造函数该函数什么都不做但允许声明数组和未初始化的对象。 2若没有提供析构函数则编译器会提供一个默认析构函数该函数什么都不做。 3若没有提供拷贝构造函数则编译器会提供一个默认的拷贝构造函数该函数进行浅拷贝。 4若没有提供赋值运算符重载则编译器会提供默认的赋值运算符重载该函数也进行浅拷贝。 5若没有提供地址运算符重载则编译器会提供默认的地址运算符重载该函数返回调用对象的地址也就是this指针的值。
4. 找出并改正下述类声明中的错误。
// nifty 类声明
class nifty
{// 数据char personality[];int talents;// 方法nifty();nifty(char* s);ostream operator(ostream os, nifty n);
};nifty::nifty()
{personality NULL;talents 0;
}nifty::nifty(char* s)
{personality new char[strlen(s)];personality s;talents 0;
}ostream nifty::operator(ostream os, nifty n)
{os n;
}答首先类声明中一般成员变量为私有成员private而成员函数为公有成员public。不显式声明时类class默认为private而结构struct默认为public。所以需要将成员函数声明为public。在默认构造函数中personality是数组名也是指向第一个元素的char指针但是其指向不能改变可以使用strcpy()函数将其初始化为空字符串参数s最好声明为const。在第二个提供一个参数的构造函数中也是同样的问题。最后一个重载运算符函数需要被声明为友元函数且该函数定义完全就是狗屁我们都还没定义你就用上了成品。根据上述问题我们通过把变量personality修改为char指针然后添加析构函数进行重写代码。当然拷贝构造函数和赋值运算符重载也是需要的读者可以自行编写
下面是正确的代码
// nifty 类声明
class nifty
{
private:// 数据char* personality;int talents;
public:// 方法nifty();nifty(const char* s);~nifty();friend ostream operator(ostream os, const nifty n);
};// 类方法定义
nifty::nifty() // 默认构造函数
{personality nullptr;talents 0;
}nifty::nifty(const char* s) // 构造函数
{int len strlen(s);personality new char[len1];strcpy(personality, s);talents 0;
}nifty::~nifty() // 析构函数
{if (personality ! nullptr)delete[]personality;
}ostream operator(ostream os, const nifty n) // 运算符重载
{os Personality: personality endl;os Talents: talents endl;return os;
}5. 对于下面的类声明回答下面的问题。
// Golfer 类声明
class Golfer
{
private:char* fullname; // 指向包含高尔夫的名称的字符串int games; // 保存玩的高尔夫游戏的个数int* scores; // 指向高尔夫分数数组的第一个元素
public:Golfer();Golfer(const char* name, int g 0);Golfer(const Golfer g);~Golfer();
};a. 下列各条语句将调用哪些类方法 1 Golfer nancy; 2 Golfer lulu(“Little Lulu”); 3 Golfer roy(“Roy Hobbs”, 12); 4 Golfer *par new Golfer; 5 Golfer next lulu; 6 Golfer hazzard “Weed Thwacker”; 7 *par nancy; 8 nancy “Nancy Putter”; b. 很明显类需要有另外几个方法才能更有用但是类需要哪些方法才能防止数据被损坏呢
答 a.
调用默认构造函数。调用一个参数的构造函数。调用两个参数的构造函数。调用默认构造函数。调用编译器提供的默认的复制构造函数。先调用一个参数的构造函数创建临时对象然后调用编译器提供的默认复制构造函数。调用编译器提供的默认的赋值运算符重载函数。先调用一个参数的构造函数创建临时对象然后调用编译器提供的默认的赋值运算符重载函数。
b. 由于编译器提供的默认的复制构造函数和赋值运算符重载函数都是浅拷贝所以需要用户自己定义复制构造函数和赋值运算符重载函数来对对象实行深度拷贝避免程序出现问题。
二、编程练习
1. 对于下面的类声明为这个类提供实现并编写一个使用所有成员函数的小程序。
// Cow 类声明
class Cow
{
private:char name[20];char* hobby;double weight;
public:Cow(); // 默认构造函数Cow(const char* nm, const char* ho, double wt);Cow(const Cow c); // 复制构造函数~Cow(); // 析构函数Cow operator(const Cow c); // 赋值运算符重载void ShowCow() const; // 显示所有有关于奶牛的数据
};答三个文件。
Cow.h头文件
#pragma once// 头文件
#include iostream// Cow 类声明
class Cow
{
private:char name[20];char* hobby;double weight;
public:Cow(); // 默认构造函数Cow(const char* nm, const char* ho, double wt);Cow(const Cow c); // 复制构造函数~Cow(); // 析构函数Cow operator(const Cow c); // 赋值运算符重载void ShowCow() const; // 显示所有有关于奶牛的数据
};main.cpp测试文件
// 头文件
#include Cow.h// using 声明
using std::cout;
using std::endl;int main()
{// 默认构造函数Cow cow1;cow1.ShowCow();cout endl;// 三个参数的构造函数Cow cow2(若雪, 干饭, 888.8);cow2.ShowCow();cout endl;// 复制构造函数Cow cow3(cow2);cow3.ShowCow();cout endl;// 赋值运算符cow3 cow1;cow3.ShowCow();cout endl;return 0;
}Cow.cpp方法定义文件
// 头文件
#include Cow.h
#include cstring// using 声明
using std::cout;
using std::endl;Cow::Cow() // 默认构造函数
{strcpy(name, 小雪);// 申请空间hobby new char[strlen(吃草) 1];strcpy(hobby, 吃草);weight 888.0;
}Cow::Cow(const char* nm, const char* ho, double wt)
{strcpy(name, nm);// 申请空间hobby new char[strlen(ho) 1];strcpy(hobby, ho);weight wt;
}Cow::Cow(const Cow c) // 复制构造函数
{strcpy(name, c.name);// 申请空间hobby new char[strlen(c.hobby) 1];strcpy(hobby, c.hobby);weight c.weight;
}Cow::~Cow() // 析构函数
{// 释放空间delete[]hobby; // 与申请的格式对应
}Cow Cow::operator(const Cow c) // 赋值运算符重载
{if (this c) // 检查是否给自己赋值{return *this;}else{strcpy(name, c.name);// 释放原来的空间delete[]hobby;// 申请新的空间hobby new char[strlen(c.hobby) 1];strcpy(hobby, c.hobby);weight c.weight;return *this;}
}void Cow::ShowCow() const // 显示所有有关于奶牛的数据
{cout Name: name endl;cout Hobby: hobby endl;cout Weight: weight endl;
}2. 通过完成下面的工作来改进String类的声明即将String1.h升级为String2.h。 a. 对运算符进行重载使之可以将两个字符串合并成一个。 b. 提供一个Stringlow()成员函数将字符串中所有的字母字符转换为小写注意cctype系列的字符函数 c. 提供String()成员函数将字符串中所有字母字符转换为大写。 d. 提供一个这样的成员函数它接受一个char参数返回该字符在字符串中出现的次数。使用下面的程序来测试你的工作。
// 头文件
#include String2.h// using 声明
using std::cin;
using std::cout;
using std::endl;int main()
{String s1( and I am a C student.);String s2 Please enter your name: ;String s3;cout s2;cin s3;s2 My name is s3;cout s2 endl;s2 s2 s1;s2.Stringupper();cout The string\n s2 \ncontains s2.ch_times(A) A characters in it.\n;s1 red;String rgb[3] { String(s1), String(green), String(blue) };cout Enter the name of a primary color for mixing light: ;String ans;bool success false;while (cin ans){ans.Stringlow();for (int i 0; i 3; i){if (ans rgb[i]){cout Thats right!\n;success true;break;}}if (success)break;elsecout Try again!\n;}cout Bye\n;return 0;
}输出应于下面相似。 Please enter your name: Fretta Farbo My name is Fretta Farbo. The string My NAME IS FRETTA FARBO AND I AM A C STUDENT. contains 6 ‘A’ characters in it. Enter the name of a primary color for misxing light: yellow Try again! BLUE That’s right! Bye
答两个文件。
String2.h头文件
#pragma once// 头文件
#include iostream// String 类声明
class String
{
private:char* str; int len; // 字符串长度static int num_strings; // 目前有多少个String对象static const int CINLIM 80; // 输入的限制
public:String(); // 默认构造函数String(const char* s);String(const String s); // 复制构造函数~String(); // 析构函数int lenth() const { return len; } // 返回字符串长度int ch_times(char key) const; // 返回字符key在字符串中出现的次数void Stringlow();void Stringupper();String operator(const char* s);String operator(const String s);char operator[](int i);const char operator[](int i) const;String operator(const String s) const;// 关系运算符重载friend bool operator(const String s1, const String s2);friend bool operator(const String s1, const String s2);friend bool operator(const String s1, const String s2);friend String operator(const char* s, const String str);friend std::ostream operator(std::ostream os, const String s);friend std::istream operator(std::istream is, String s);// 静态成员函数static int HowMany();
};String2.cpp方法定义文件
// 头文件
#include String2.h
#include cctype
#include cstring// using 声明
using std::endl;// 静态成员变量初始化
int String::num_strings 0;String::String() // 默认构造函数
{str nullptr;len 0;num_strings;
}String::String(const char* s)
{len strlen(s);// 申请空间str new char[len 1];strcpy(str, s);num_strings;
}String::String(const String s) // 复制构造函数
{len s.len;// 申请空间str new char[len 1];strcpy(str, s.str);num_strings;}String::~String() // 析构函数
{// 释放空间if (str ! nullptr)delete[]str;
}int String::ch_times(char key) const // 返回字符key在字符串中出现的次数
{int times 0;for (int i 0; i len; i){if (str[i] key)times;}return times;
}void String::Stringlow()
{for (int i 0; i len; i){str[i] tolower(str[i]);}
}void String::Stringupper()
{for (int i 0; i len; i){str[i] toupper(str[i]);}
}String String::operator(const char* s)
{len strlen(s);// 释放之前的空间delete[]str;// 申请新的空间str new char[len 1];strcpy(str, s);return *this;
}String String::operator(const String s)
{len s.len;// 释放之前的空间delete[]str;// 申请新的空间str new char[len 1];strcpy(str, s.str);return *this;
}char String::operator[](int i)
{return str[i];
}const char String::operator[](int i) const
{return str[i];
}String String::operator(const String s) const
{int total len s.len;// 申请空间char* result new char[total 1];strcpy(result, str);strcat(result, s.str);String tmp(result);// 释放空间delete[]result;return tmp;
}String operator(const char* s, const String str)
{int total strlen(s) str.len;// 申请空间char* result new char[total 1];strcpy(result, s);strcat(result, str.str);String tmp(result);// 释放空间delete[]result;return tmp;
}// 关系运算符重载
bool operator(const String s1, const String s2)
{return (strcmp(s1.str, s2.str) 0);
}bool operator(const String s1, const String s2)
{return s2 s1;
}bool operator(const String s1, const String s2)
{return !strcmp(s1.str, s2.str);
}std::ostream operator(std::ostream os, const String s)
{if (s.str ! nullptr){os s.str;}return os;
}std::istream operator(std::istream is, String s)
{char tmp[String::CINLIM];is.getline(tmp, String::CINLIM);if (!is){is.clear();while (is.get() ! \n)continue;return is;}s tmp;return is;
}// 静态成员函数
int String::HowMany()
{return num_strings;
}运行结果
3. 重写程序清单10.7和程序清单10.8描述的Stock类使之使用动态分配的内存而不是string类对象来存储股票名称。另外使用重载的operator()定义代替show()成员函数。再使用程序清单10.9测试新的程序。
答使用动态内存分配可以使用char*指针也可以使用指向string类的指针。在构造函数中申请空间在析构函数中释放空间申请和释放的形式需要匹配。
Stock.h头文件
#pragma once// 头文件
#include iostream// Stock 类声明
class Stock
{
private:char* company; // 股票公司名称int shares; // 股票数量double share_val; // 每份股票double total_val; // 总值void set_tot() { total_val share_val * shares; } // 设置总值
public:Stock(); // 默认构造函数Stock(const char* co, int n, double pr);~Stock(); // 析构函数void buy(int num, double pr); // 买进void sell(int num, double pr); // 卖出void update(double pr); // 更新价格// 运算符重载friend std::ostream operator(std::ostream os, const Stock s);const Stock topval(const Stock s) const; // 返回总值大的对象
};main3.cpp测试文件
// 头文件
#include Stock.h// using 声明
using std::cin;
using std::cout;
using std::endl;// 符号常量声明
const int STKS 4;int main()
{Stock stocks[STKS] {Stock(NanoSmart, 12, 20.0),Stock(Boffo Objects, 200, 2.0),Stock(Monolithic Obelisks, 130, 3.25),Stock(Fleep Enterprises, 60, 6.5)};// 显示所有股票cout Stock holdings:\n;for (int i 0; i STKS; i)cout stocks[i];// 找出总值最大的股票const Stock* top stocks[0];for (int i 1; i STKS; i)top top-topval(stocks[i]);cout \nMost valuable holding:\n;cout *top endl;return 0;
}Stock.cpp方法定义文件
// 头文件
#include Stock.h
#include cstring// using 声明
using std::cout;
using std::endl;Stock::Stock() // 默认构造函数
{company nullptr;shares 0;share_val 0;set_tot();
}Stock::Stock(const char* co, int n, double pr)
{// 申请空间拷贝公司名称int len (int)strlen(co);company new char[len 1];strcpy(company, co);// 赋值其他成员shares n;share_val pr;set_tot();
}Stock::~Stock() // 析构函数
{// 释放申请空间if (company ! nullptr)delete[]company;
}void Stock::buy(int num, double pr) // 买进
{if (num 0){shares num;share_val pr;set_tot();}else{cout 买进股票的数量不能为负;}
}void Stock::sell(int num, double pr) // 卖出
{if (num 0){cout 卖出股票的数量不能为负;}else if (num shares){cout 卖出股票的数量不能超过自身拥有的股票数量;}else{shares - num;share_val pr;set_tot();}
}void Stock::update(double pr) // 更新价格
{share_val pr;
}// 运算符重载
std::ostream operator(std::ostream os, const Stock s)
{os Company: s.company;os Shares: s.shares endl;os Share Price: $ s.share_val;os Total Worth: $ s.total_val endl;return os;
}const Stock Stock::topval(const Stock s) const // 返回总值大的对象
{if (total_val s.total_val)return *this;elsereturn s;
}4. 请看程序清单10.10定义的Stack类的变量。
#pragma once// 头文件
#include iostream// 类型声明
typedef unsigned long Item;// Stack 类声明
class Stack
{
private:enum { MAX 10 };Item* pitems;int size;int top;
public:Stack(int n MAX);Stack(const Stack st);~Stack();bool isempty() const;bool isfull() const;bool push(const Item item);bool pop(Item item);Stack operator(const Stack st);void get_info() const;
};正如私有成员表明的这个类使用动态分配的数组来保存栈中的项。请重新编写方法以适应这种新的表示方法并编写一个程序来演示所有的方法包括复制构造函数和赋值运算符。
答头文件上面有这里就提供测试文件和方法定义文件。
main4.cpp测试文件
// 头文件
#include Stack.h// using 声明
using std::cout;
using std::endl;int main()
{// 默认构造函数Stack stack1;for (int i 0; i 5; i){stack1.push(i);}stack1.get_info();cout endl;// 复制构造函数Stack stack2(stack1);stack2.get_info();cout endl;Item tmp;stack2.pop(tmp);stack2.pop(tmp);stack2.get_info();cout endl;// 赋值运算符stack1 stack2;stack1.get_info();return 0;
}Stack.cpp方法定义文件
// 头文件
#include Stack.h// using 声明
using std::cout;
using std::endl;Stack::Stack(int n)
{if (n MAX){size MAX;}else if (n 0){size n;}else{cout 栈的大小不能为非正整数\n;size top 0;pitems nullptr;return;}// 申请空间pitems new Item[size];top 0;
}Stack::Stack(const Stack st)
{size st.size;// 申请空间pitems new Item[size];top st.top;// 复制每个元素for (int i 0; i top; i)pitems[i] st.pitems[i];
}Stack::~Stack()
{// 释放空间if (pitems ! nullptr)delete pitems;
}bool Stack::isempty() const
{return top 0;
}bool Stack::isfull() const
{return top size;
}bool Stack::push(const Item item)
{if (!isfull()){pitems[top] item;return true;}else{return false;}
}bool Stack::pop(Item item)
{if (!isempty()){item pitems[--top];return true;}else{return false;}
}Stack Stack::operator(const Stack st)
{if (st this){return *this;}else{// 释放之前的空间delete[]pitems;// 申请新的空间size st.size;pitems new Item[size];// 赋值内容top st.top;for (int i 0; i top; i){pitems[i] st.pitems[i];}return *this;}
}void Stack::get_info() const
{if (pitems ! nullptr){for (int i 0; i top; i){cout pitems[i] ;}}
}
后面两题的答案作者没写因为目前不是很懂这些编程练习的答案都是我自己写的然后运行验证的。作者今天就不加班了偷个懒明天早上把这两道题补上。