类的抽象、类的数据表示、类的实现、对象的使用
1、使用伪随机数加密的算法,按要求实现:
伪随机数加密的算法:根据一个给定的伪随机数种子,就可以得到无穷多个伪随机数。
伪随机数种子固定,得到的这个伪随机数数列就是固定的。
设有一个要加密的数列,X0,X1,X2,X3,…,也称明文,
一个给定的伪随机数种子 Seed.
加密:
根据种子Seed,可得到伪随机数数列 Y0,Y1,Y2,Y3,…,
通过计算可得到另一个数列,Z0,Z1, Z2, Z3,…,
其中Zi=Xi XOR Yi,(Xi 异或 Yi)
这样Zi数列就是一个对原始数列X0,X1,X2,X3,…的加密,
Z0,Z1, Z2, Z3,…,也称密文,seed就是密钥。
解密:
根据种子Seed,仍可得到伪随机数数列 Y0,Y1,Y2,Y3,…,
同上通过计算可得到另一个数列,X0,X1, X2, X3,…,
其中Xi=Yi XOR Zi,(Yi 异或 Zi),
这样Xi数列就是一个对加密数列Z0,Z1,Z2,Z3,…的解密,
Xi就是加密前的明文。
下面的TRandom类是用线性调和算法,实现的一个伪随机数发生器,仔细阅读代码,理解其含义。
线性调和算法的基本原理是:对于给定的N、M和K,任给一个X,
不断用X=((N*X+M) mod K )进行迭代计算,那么得到的无穷多个x值,
近似于在(0,K)上的均匀分布.其中N,M,K为较大的数(N最好是素数).
#include
#include
//#include
//#include
class TRandom
{
public:
//缺省使用系统时间(开机后经过的毫秒数)为种子
TRandom (long seed=0) { mSeed=(seed?seed: GetTickCount()); }
//也可以定义自己的种子
void Seed(long seed=0) { mSeed=(seed?seed: GetTickCount( )); }
//取得一个随机的整数
int Integer() { return Next();}
//取得一个在指定范围内的随机整数
int Integer(int min,int max) { return min+Next()%(max-min+1);}
//取得一个随机的(0到1之间的)小数
double Real() {return double(Next())/double(INT_MAX);}
private:
//使用调和算法
void Change() {mSeed=(314159265*mSeed+13579)%ULONG_MAX;}
//取得伪随机数发生器的随机数序列中的下一个随机整数
int Next() {
int loops=mSeed%3;
for (int i=0;i<=loops;i++)
Change ();
return int(mSeed/2);
}
unsigned long mSeed; //随机数发生器的种子
};
1)利用上面提到的TRandom类,实现指定全局函数,以便完成字节数组的加密和解密。
void Coder(unsigned char data[],int len, unsinged long key);
void Coder(unsigned char data[], int len, unsigned long key) {
TRandom rand(key);
for (int i = 0; i < len; i++) {
data[i] ^= rand.Integer() % 256;
}
2)利用上面提到的TRandom类,实现指定全局函数,以便完成字节数组的加密和解密。
void Coder(unsigned char data[],int len, TRandom& rand, unsinged long key);
void Coder(unsigned char data[], int len, TRandom& rand, unsigned long key) {
rand.Seed(key);
for (int i = 0; i < len; i++) {
data[i] ^= rand.Integer() % 256;
}
}
void Decoder(unsigned char data[], int len, TRandom& rand, unsigned long key) {
rand.Seed(key);
for (int i = 0; i < len; i++) {
data[i] ^= rand.Integer() % 256;
}
}
3)将第二问中的TRandom& rand,改成TRandom rand,结果改变了吗?为什么?
结果不变。因为在函数中对rand修改时,实际上修改的是原对象而非传递的副本。
4)将第二问中的TRandom& rand,改成const TRandom& rand,行吗?为什么?
不可行,每生成一次随机数mSeed都会改变
5)如何定义一个加密/解密器类(Crypter),来实现同样功能呢?
class Crypter {
public:
Crypter(unsigned long key) : rand(key) {}
void encode(unsigned char data[], int len) {
for (int i = 0; i < len; i++) {
data[i] ^= rand.Integer() % 256;
}
}
void decode(unsigned char data[], int len) {
for (int i = 0; i < len; i++) {
data[i] ^= rand.Integer() % 256;
}
}
private:
TRandom rand;
};
使用示例:
Crypter crypter(12345); // 初始化加密/解密器,指定密钥为12345
unsigned char data[] = "Hello World!"; // 待加密/解密的数据
int len = sizeof(data) - 1; // 数据长度
crypter.encode(data, len); // 加密
printf("%s", data);
crypter.decode(data, len); // 解密
printf("%s", data);
2.练习根据给定的描述,抽象出类,给出适当的数据成员和成员函数,并给出具体的类定义和实现。
书的主要功能有:取得总页数;今天读了指定页数;取得累计读了多少页;取得剩余多少也未读;
类定义:
class Book {
private:
int totalPages;
int pagesReadToday;
int pagesReadTotal;
public:
Book(int totalPages);
int getTotalPages();
void readPages(int pages);
int getPagesReadToday();
int getPagesReadTotal();
int getPagesLeft();
};
类实现:
Book::Book(int totalPages) {
this->totalPages = totalPages;
this->pagesReadToday = 0;
this->pagesReadTotal = 0;
} //构造函数,初始化书的总页数为totalPages,累计读的页数和今天读的页数为0
int Book::getTotalPages() {
return this->totalPages;
}//返回书的总页数
void Book::readPages(int pages) {
this->pagesReadToday += pages;
this->pagesReadTotal += pages;
}//将今天读的页数加上pages,累计读的页数也加上pages
int Book::getPagesReadToday() {
return this->pagesReadToday;
}//返回今天读的页数
int Book::getPagesReadTotal() {
return this->pagesReadTotal;
}//返回累计读的页数
int Book::getPagesLeft() {
return this->totalPages - this->pagesReadTotal;
}//返回剩余未读的页数
3、请给出Card类的定义和实现:
只用一副无大小王的扑克,扑克的花色(suit)分为 Spade、Heart、Diamond和Club,
每门花色的牌共13张,面值(rank)分别为 2、3、4、5、6、7、8、9、10、Jack、
Queen、King和Ace,每张扑克牌应包含 如下信息:唯一的ID号(0-51)、花色、面值、
背面图案的编号、扑克牌的宽度、扑克牌的高度、扑克牌的左顶点坐标等。
扑克牌的操作有:存取背面图案,判断与另一张扑克牌是相同花色吗? 判断与另一张扑克牌是相同面值吗?判断扑克牌是给指定的花色吗?
判断扑克牌是给指定的面值吗?设置扑克牌坐标,取得扑克牌的右下角坐标等.
1)请写出扑克牌类Card类的定义和实现,要求选取适当形式的数据成员
描述每张扑克牌的信息,同时以成员函数的形式实现指定的操作。
enum Suit { Spade, Heart, Diamond, Club };
enum Rank { Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace };
//枚举类型,Two初始值定为2,后面的值依次递增
class Card {
private:
int id;
Suit suit;
Rank rank;
int back_id;
int width;
int height;
int x;
int y;
public:
Card(int _id, Suit _suit, Rank _rank, int _back_id, int _width, int _height, int _x, int _y)
: id(_id), suit(_suit), rank(_rank), back_id(_back_id), width(_width), height(_height), x(_x), y(_y) {}
Suit get_suit() const { return suit; }
Rank get_rank() const { return rank; }
bool is_same_suit(const Card& other) const { return suit == other.suit; }
bool is_same_rank(const Card& other) const { return rank == other.rank; }
bool is_given_suit(Suit given_suit) const { return suit == given_suit; }
bool is_given_rank(Rank given_rank) const { return rank == given_rank; }
void set_coordinates(int new_x, int new_y) { x = new_x; y = new_y; }
int get_right_bottom_x() const { return x + width; }
int get_right_bottom_y() const { return y + height; }
};
2)给Card类添加一个显式的拷贝构造函数并实现它。
Card(const Card& other): id(other.id), suit(other.suit), rank(other.rank), back_id(other.back_id), width(other.width), height(other.height), x(other.x), y(other.y) {}
4、练习根据给定的描述,抽象出类,给出适当的数据成员和成员函数,并给出具体的类定义。
游戏中的英雄有各自的魅力值、声望值、攻击力、防御力、法力等,每个英雄可以最多带5个宝物, 每种宝物有特有提升英雄某种能力的效果。游戏中假设共有6种宝物(暂时用1,2,3,…6代表,1提升魅力2点,2提升声望3点,3提升攻击力1点,…),英雄这个类需要有功能:取得当前状态下的各种能力值,在指定位置中携带指定宝物,丢弃指定位置中的宝物等。
class Hero {
public:
int getcharm() {
return this->charm;
}
int getprestige() {
return this->prestige;
}
int getattack() {
return this->attack;
}
int getdefense() {
return this->defense;
}
int getmagic() {
return this->magic;
}
int* getTreasure() {
return this->treasure;
}
void CarryTreasure(int position, int Treasure) {
if (position < 0 || position > 5) return;
else if (treasure[position] == 0) treasure[position] = Treasure;
else {
cout << "此位置已经有宝物,请更换空间存储";
return;
}
}
void DropTreasure(int position) {
if (position >= 0 && position <= 5) {
treasure[position] = 0;
}
else return;
}
private:
int charm;
int prestige;
int attack;
int defense;
int magic;
int treasure[5] = {0};
};
5.已知类Demo的类定义如下,请改写Demo类,使得无论如何,用户至多只能创建并访问Demo类的唯一一个实例。 ————注:使用单例模式!
class Demo {
public:
Demo( ) { mNum = 0; }
void AddValue(int value) { mNum+=value;}
void ShowValue( ) const { cout<<"Value="<
class Demo{
public:
static Demo& GetExam () {
static Demo temp;
return temp;
}
void AddValue(int value) { mNum += value; }
void ShowValue() const { cout << “value=” << value << endl; }
private:
Demo() {mNum = 0};
Demo(const Demo&)= delete;
Demo& operator=(const Demo&) = delete;
int mNum;
};
6.一个游戏中有很多怪物(Monster),怪物之间可能要发生战斗(fight),
每场战斗都是一个怪物与另一怪物之间的一对一战斗。每个怪物都有自己
的速度(Speed)、生命值(hitpoint)、攻击力值(damage)和防御力值(defense);
战斗时,两个怪物依次攻击对方,即怪物a首先攻击怪物b, 然后轮到怪物b
攻击怪物a,之后,怪物a再次攻击怪物b,…,直到一方生命值为0;
战斗时,由速度快的一方首先发起攻击;若速度一样,比较生命值,由高者首先攻击;
若生命值也相等,比较攻击力,由高者首先攻击;若攻击力还相等,比较防御力,由
高者首先攻击;若四项都相等,则选择任一方首先攻击;
怪物A攻击怪物B时,会给怪物B造成伤害,使得怪物B的生命值降低,降低值为:
2*A的攻击力-B的防御力,最小为1。
请根据你对上述描述的理解,定义并实现怪物类Monster,成员的设计可以任意,
但要求该类至少有一个成员函数fight,用来描述与另外一个怪物进行战斗的过程。
不必考虑怪物的生命值减少至0后如何处理。
类的定义:
Class Monster{
public:
Monster(int sp, int hit, int dam, int def) : speed(sp), hitpoint(hit), damage(dam), defense(def) {}
void fight(Monster& other);
private:
int speed;
int hitpoint;
int damage;
int defense;
};
Fight函数外联实现:
void Monster::fight(Monster& other) {
Monster& attacker = (speed > other.speed) ? (*this) : ((speed < other.speed) ? other :
(hitpoint > other.hitpoint) ? (*this) : ((hitpoint < other.hitpoint) ? other : (damage > other.damage) ? (*this) : ((damage < other.damage) ? other : (defense > other.defense) ? (*this) : other)));
Monster& defender = (&attacker == (*this)) ? other : (*this);
int hurt = max{ 2 * attacker.damage – defender.defense, 1};
defender.hitpoint -= hurt;
}