【感谢@m0_68850366对第五题和第八题的指导】
- 贼(Thief)偷窃行人,每个行人都有随身带的钱,贼偷窃一个行人,他的钱就增加相应的钱包里的钱数。
请给出Thief类和Walker类。
#include <bits/stdc++.h>
using namespace std;
class Walker{
friend class Thief;
public:
Walker(int x) {
w_money = x;
}
private: int w_money;
};//Walker类
class Thief{
public:
void get() {
cout << m_money;
}
void steal(Walker w) {
m_money += w.w_money;
}
private:
int m_money = 0;
};//Thief类
//测试代码
int main()
{
Thief p1;
Walker p2(3);
p1.steal(p2);
p1.get();
return 0;
}
-
警察局有多名警察,每个警察抓获一名贼,警察局的声望就增加1点,该警察的奖金就增加100元,贼的金钱减为0。
请实现相关的警察局、警察、贼的类。
用例可为:警察局S有警察p1,p2,p3,贼有t1,t2,t3,t4, p1抓获t2,t3, p2抓获t4, p3没抓获任何贼。t1的初始金钱为500,
t2的初始金钱为800,t3的初始金钱为300,t4的初始金钱为1000,S的初始声望为100,警察的初始奖金为0。
输出最终S的声望,每个警察的奖金数。
#include <bits/stdc++.h>
using namespace std;
class thief{
public:
thief(int x) : money(x) {}
int get() {
return money;
}
void beingcaught() {//这里函数无需添加policeman的参数(依赖关系单向即可实现)
money = 0;
}
int money;
};
class policeman{
public:
policeman() : bonus(0) {}
int arrest(thief t) {//thief类的对象作为函数参数,为依赖关系
bonus += t.money;
t.beingcaught();
}
int get() {
return bonus;
}
private:
int bonus;
};
class policeoffice{
public:
void addpoliceman(policeman x) {
p.push_back(x);
}
int get() {
return reputation;
}
void m_catch(thief t, policeman& p) {//这里policeman一定是传引用,否则无法反馈到主函数中实例化出来policeman的bonus值。
p.arrest(t);
reputation++;
}
private:
int reputation = 100;
vector<policeman> p;
};
int main()
{
policeoffice s;
policeman p1, p2, p3;
s.addpoliceman(p1);
s.addpoliceman(p2);
s.addpoliceman(p3);
thief t1(500), t2(800), t3(300), t4(1000);
s.m_catch(t2, p1);
s.m_catch(t3, p1);
s.m_catch(t4, p2);
cout << "警察局的声望为:"<< s.get() << endl;
cout << "p1的奖金为" << p1.get() << endl;
cout << "p2的奖金为" << p2.get() << endl;
cout << "p3的奖金为" << p3.get() << endl;
return 0;
}
- 在2的基础上,再加上1中的类,试一试。
#include <iostream>
#include <vector>
using namespace std;
class Walker {
public:
//Walker(){}
Walker(int x) {
w_money = x;
}
int w_money;
};//Walker类
class thief {
public:
thief(int x) : money(x) {}
int get() {
return money;
}
void steal(Walker a) {
money += a.w_money;
}
void beingcaught() {//这里函数无需添加policeman的参数(依赖关系单向即可实现)
money = 0;
}
int money;
};
class policeman {
public:
policeman() : bonus(0) {}
void arrest(thief t) {//thief类的对象作为函数参数,为依赖关系
bonus += t.money;
t.beingcaught();
}
int get() {
return bonus;
}
private:
int bonus;
};
class policeoffice {
public:
void addpoliceman(policeman x) {
p.push_back(x);
}
int get() {
return reputation;
}
void m_catch(thief t, policeman& p) {//这里policeman一定是传引用,否则无法反馈到主函数中实例化出来policeman的bonus值。
p.arrest(t);
reputation++;
}
private:
int reputation = 100;
vector<policeman> p;
};
int main()
{
policeoffice s;
policeman p1, p2, p3;
s.addpoliceman(p1);
s.addpoliceman(p2);
s.addpoliceman(p3);
thief t1(500), t2(800), t3(300), t4(1000);
Walker w1(100);
t2.steal(w1);
s.m_catch(t2, p1);
s.m_catch(t3, p1);
s.m_catch(t4, p2);
cout << "警察局的声望为:" << s.get() << endl;
cout << "p1的奖金为" << p1.get() << endl;
cout << "p2的奖金为" << p2.get() << endl;
cout << "p3的奖金为" << p3.get() << endl;
return 0;
}
4.用简单双向关联和关联类的形式分别实现男人(Man)和女人(Woman)间的一对一关系。
一个未婚男人可以和一个未婚女人结婚;
一个已婚男人可以其妻子离婚;
一个未婚女人可以和一个未婚男人结婚;
一个已婚女人可以其丈夫离婚;
一个已婚男人可以“知道”其妻子;
一个已婚女人可以“知道”其丈夫;
//双向关联实现:
class Woman;
class Man {
public:
void marry(Woman& wife) {
if (!married && !wife.married) {
this->wife = &wife;
wife.husband = this;
married = true;
wife.married = true;
}
}
void divorce() {
if (married) {
wife->married = false;
wife->husband = nullptr;
wife = nullptr;
married = false;
}
}
Woman* getWife() { return wife; }
private:
bool married = false;
Woman* wife = nullptr;
};
class Woman {
public:
void marry(Man& husband) {
if (!married && !husband.married) {
this->husband = &husband;
husband.wife = this;
married = true;
husband.married = true;
}
}
void divorce() {
if (married) {
husband->married = false;
husband->wife = nullptr;
husband = nullptr;
married = false;
}
}
Man* getHusband() { return husband; }
private:
bool married = false;
Man* husband = nullptr;
};
//关联类实现:
class Woman;
class Man {
friend class Marriage;
public:
void marry() {
married = true;
}
void divorce() {
married = false;
}
void setWife(Woman* wife) {
this->wife = wife;
}
Woman* getWife() {
return wife;
}
private:
bool married = false;
Woman* wife = nullptr;
};
class Woman {
friend class Marriage;
public:
void marry(){
married = true;
}
void divorce() {
married = false;
}
void setHusband(Man* husband) {
this->husband = husband;
}
Man* getHusband() {
return husband;
}
private:
bool married = false;
Man* husband = nullptr;
};
class Marriage {
public:
static void arrange(Man& man, Woman& woman);
static void divorce(Man& man);
};
void Marriage::arrange(Man& man, Woman& woman) {
if (!man.married && !woman.married) {
man.setWife(&woman);
woman.setHusband(&man);
man.marry();
woman.marry();
}
}
void Marriage::divorce(Man& man) {
if (man.married) {
Woman* wife = man.getWife();
man.setWife(nullptr);
wife->setHusband(nullptr);
man.divorce();
wife->divorce();
}
}
5.现有类A和类B
class A {
public:
A(int num):mData(num){ }
~A( ) { }
int GetData( ) const { return mData; }
void SetData(int data) { mData = data; }
private:
int mData;
};
class B {
public:
B(int num=0):pa(new A(num)) { }
~B( ) {delete pa;}
B(const B& rhs) {
pa=new A(*rhs.pa);
}
B& operator=(const B& rhs) {
if ( this!=&rhs ) {
delete pa;
pa=new A(rhs.pa);
}
return this;
}
A operator->( ) const {return pa;}
void GetData() const { return pa->GetData();}
void SetData(int data) { pa->SetData(data); }
private:
A pa;
};
a)现需要以引用计数的方法,重新实现类B,要求类A不得做任何修改。
b)请在a)的基础上,以Copy On Write的方式修改类B的实现,
使得B类对象可以访问成员B类的成员SetData(int);(即可以修改
B类对象中pa指针指向的A类对象的数据成员。也就是说,使用B类对象时,
对于以只读方式访问A类的成员,使用引用计数;
对于以写方式访问A类的成员,要先进行深赋值,然后再写数据)。
#include<iostream>
using namespace std;
class A {
public:
A(int num):mData(num){ }
~A( ) { }
int GetData( ) const { return mData; }
void SetData(int data) { mData = data; }
private:
int mData;
};
class B {
public:
B(int num=0);
~B( );
B(const B& rhs);
B& operator=(const B& rhs);
void AddRef()
{
(*puse)+=1;
}
void ReleaseRef()
{
if(--(*puse)==0)
{
delete pa;
delete puse;
}
}
A* operator->( ) const {return pa;}
int GetData() const { return pa->GetData();} //读函数没啥问题,下面的写函数需要做一个修改
void SetData(int data);
private:
A* pa;
int * puse; //用来存续计数数值
};
B::B(int num)
{
pa=new A(num);
puse=new int(1); //创建时计数为1
}
B::~B()
{
// delete pa;
// if(ReleaseRef()==0)
// delete puse; //这里的写法是错误的,应该在puse指向计数为0时,才把两个指针都释放
ReleaseRef();
}
B::B(const B& rhs)
{
pa=rhs.pa;
puse=rhs.puse;
AddRef(); //引用计数时拷贝不是深拷贝
}
B& B::operator=(const B& rhs)
{
if(this!=&rhs) //注意这里判别自赋值的写法,考虑的是地址!!!!!!
{
ReleaseRef(); //引用计数时赋值不是深赋值
pa=rhs.pa;
puse=rhs.puse;
}
return *this;
}
void B::SetData(int n)
{
if(*puse==1) //被修改对象引用次数为1,直接修改
pa->SetData(n);
else
{
ReleaseRef(); //这里的目的只是让计数值减1
pa=new A(*pa); //注意这里别写A(n),当A中有其他数据时,我们仅仅只对mData进行了修改,复制内容,开辟一块新的空间(复制的时候并不会自己开辟新空间,因为时浅拷贝),让指针指向新的A
puse=new int(1); //新的计数1
pa->SetData(n);
}
}
6.若程序中需要频繁地用new创建、用delete销毁A类对象,请在A类中通过
重载operator new和operator delete,实时统计创建A类对象的个数、销毁的个数、
累计分配的字节数、还在使用的字节数。
若还可能使用new[],delete[],如何也能完成上边的统计工作。
#include <iostream>
#include <cstring>
using namespace std;
class A {
private:
static int n_alloc; // 已分配个数
static int n_dealloc; // 已释放个数
static size_t bytes_allocated; // 已分配字节数
static size_t bytes_in_use; // 仍在使用字节数
public:
void* operator new(size_t size) {
void* p = ::operator new(size);
n_alloc++;
bytes_allocated += size;
bytes_in_use += size;
return p;
}
void operator delete(void* p, size_t size) noexcept {
n_dealloc++;
bytes_in_use -= size;
::operator delete(p);
}
static int getNAlloc() { return n_alloc; }
static int getNDealloc() { return n_dealloc; }
static size_t getBytesAllocated() { return bytes_allocated; }
static size_t getBytesInUse() { return bytes_in_use; }
// 如果还需要支持 new[] 和 delete[],可以添加下列代码
void* operator new[](size_t size) {
void* p = ::operator new[](size);
n_alloc++;
bytes_allocated += size;
bytes_in_use += size;
return p;
}
void operator delete[](void* p, size_t size) noexcept {
n_dealloc++;
bytes_in_use -= size;
::operator delete[](p);
}
};
int A::n_alloc = 0;
int A::n_dealloc = 0;
size_t A::bytes_allocated = 0;
size_t A::bytes_in_use = 0;
int main() {
A* p1 = new A();
A* p2 = new A[3];
cout << "n_alloc: " << A::getNAlloc() << endl;
cout << "n_dealloc: " << A::getNDealloc() << endl;
cout << "bytes_allocated: " << A::getBytesAllocated() << endl;
cout << "bytes_in_use: " << A::getBytesInUse() << endl;
delete p1;
delete[] p2;
cout << "n_alloc: " << A::getNAlloc() << endl;
cout << "n_dealloc: " << A::getNDealloc() << endl;
cout << "bytes_allocated: " << A::getBytesAllocated() << endl;
cout << "bytes_in_use: " << A::getBytesInUse() << endl;
return 0;
}
7.通过分析二元运算符的交换律,以及左操作数的限制,理解
1)为什么重载+,一般用自由函数形式?
+是二元运算符,经常用于两个东西相加,因此一般采用自由函数形式。
2) 为什么重载+=,一般用成员函数形式?
+=表示在原来数据的基础上再加上某数据,使用成员函数形式可以利用this指针来较好地完成这一功能。
3)为什么重载=,必须用成员函数形式?
重载=需要涉及该对象的内部状态(修改数据成员的值等)
4)为什么重载<<,必须用自由函数形式?
<<是左操作数限制,其左操作数必须是std::ostream类型的对象,若是定义为成员函数则会导致类似于x << cout这样的问题,显然这并非我们的要求。因此只能定义为自由函数形式。
8.实现课堂上讲解的分页器类(Paginate),不用实现输入指定页的部分。
如:
对于如下主函数:
int main()
{
Paginate pager(1,13);
for(int i=1;i<=13;++i) {
//i当前页,13总页数
pager.setPage(i,13).show();
}
cout<<“start move…”<<endl;
pager.setPage(5,13).show();
pager.next().show();
pager.prev().show();
//直接翻5页
pager.nextN().show();
pager.next().show();
pager.prevN().show();
return 0;
}
其输出为:(+表示是当前页)
上页 1+ 2 3 4 5 … 13 下页
上页 1 2+ 3 4 5 … 13 下页
上页 1 2 3+ 4 5 … 13 下页
上页 1 2 3 4+ 5 … 13 下页
上页 1 2 3 4 5+ … 13 下页
上页 1 … 6+ 7 8 9 10 … 13 下页
上页 1 … 6 7+ 8 9 10 … 13 下页
上页 1 … 6 7 8+ 9 10 … 13 下页
上页 1 … 6 7 8 9+ 10 … 13 下页
上页 1 … 6 7 8 9 10+ … 13 下页
上页 1 … 9 10 11+ 12 13 下页
上页 1 … 9 10 11 12+ 13 下页
上页 1 … 9 10 11 12 13+ 下页
start move…
上页 1 2 3 4 5+ … 13 下页
上页 1 … 6+ 7 8 9 10 … 13 下页
上页 1 2 3 4 5+ … 13 下页
上页 1 … 6 7 8 9 10+ … 13 下页
上页 1 … 9 10 11+ 12 13 下页
上页 1 … 6+ 7 8 9 10 … 13 下页
#include<iostream>
using namespace std;
class Paginate{
public:
Paginate(int i,int j); //构造函数
Paginate& setPage(int i,int j); //设置当前分页器的状态
void show(); //输出分页器的状态
Paginate& prev(); //前翻
Paginate& next(); //后翻
Paginate& prevN(); //前翻5页
Paginate& nextN(); //后翻5页
private:
int num; //当前页数
int total; //总页数
int rangeStart; //当前显示页数头(除去首页和尾页)
int rangeEnd; //当前显示页数尾(除去首页和尾页)
};
Paginate::Paginate(int i,int j)
{
this->setPage(i,j);
}
Paginate& Paginate::setPage(int i,int j)
{
num=i;
total=j;
if(j==1)
{
rangeStart=1;
rangeEnd=1;
}
else if(j==2)
{
rangeStart=1;
rangeEnd=1;
}
else if(j>=3&&j<=6)
{
rangeStart=2;
rangeEnd=j-1;
}
else if(j>=7&&j<=10)
{
if(1<=num&&num<=5)
{
rangeStart=2;
rangeEnd=5;
}
else
{
rangeStart=j-4;
rangeEnd=j-1;
}
}
else if(j>=11)
{
if(1<=num&&num<=5)
{
rangeStart=2;
rangeEnd=5;
}
else if(num<=j&&num>=j-j%5+1)
{
rangeStart=j-4;
rangeEnd=j-1;
}
else
{
int k=num%5-1;
if(k==-1)
k=4;
rangeStart=num-k;
rangeEnd=rangeStart+4;
if(rangeEnd==total)
rangeEnd-=1;
}
}
return *this;
}
void Paginate::show()
{
cout<<"上页"<<" ";
if(total==1)
cout<<"1+ ";
else if(total==2)
{
for(int i=1;i<=2;i++)
{
if(i==num)
cout<<i<<"+ ";
else
cout<<i<<" ";
}
}
else
{
if(num==1)
cout<<"1+ ";
else
cout<<"1 ";
if(rangeStart>2)
cout<<"... ";
for(int i=rangeStart;i<=rangeEnd;i++)
{
if(i==num)
cout<<i<<"+ ";
else
cout<<i<<" ";
}
if(rangeEnd<total-1)
cout<<"... ";
if(num==total)
cout<<total<<"+ ";
else
cout<<total<<" ";
}
cout<<"下页"<<endl;
}
Paginate& Paginate::prev()
{
if(num>1)
this->setPage(num-1,total);
return *this;
}
Paginate& Paginate::prevN()
{
if(num>5)
this->setPage(num-5,total);
else
this->setPage(1,total);
return *this;
}
Paginate& Paginate::next()
{
if(num<total)
this->setPage(num+1,total);
return *this;
}
Paginate& Paginate::nextN()
{
if(num<=total-5)
this->setPage(num+5,total);
else
this->setPage(total,total);
return *this;
}
int main()
{
Paginate pager(1,13);
for(int i=1;i<=13;++i) {
//i当前页,13总页数
pager.setPage(i,13).show();
}
cout<<"start move...."<<endl;
pager.setPage(5,13).show();
pager.next().show();
pager.prev().show();
//直接翻5页
pager.nextN().show();
pager.next().show();
pager.prevN().show();
return 0;
}
注意输出的格式需与题签中的完全一致,包括省略号!