2022级吉林大学面向对象第四次上机测试

【感谢@m0_68850366对第五题和第八题的指导】

  1. 贼(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. 警察局有多名警察,每个警察抓获一名贼,警察局的声望就增加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;
}
  1. 在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;
}

注意输出的格式需与题签中的完全一致,包括省略号!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值