友元
友元函数
一个类的友元函数可以访问该类的私有成员
class CCar ; class CDriver { public : void ModifyCar (CCar * pCar) ; }; class CCar { private : int price; friend int MostExpensiveCar (CCar cars[], int total) ; friend void CDriver::ModifyCar(CCar * pCar); }; void CDriver::ModifyCar(CCar * pCar){ pCar->price += 1000 ; } int MostExpensiveCar (CCar cars[], int total) { int tmpMax = -1 ; for (int i = 0 ; i < total; ++i){ if (cars[i].price > tmpMax) tmpMax = cars[i].price; } return tmpMax; } int main () { return 0 ; }
还可以将一个类的成员函数定义为另一个类的友元函数
class B { public : void function () ; }; class A { friend void B::function(); }
这种方式使得在class A中也可以通过class B的function访问到B的私有成员。
友元类
类A如果是B的友元类,那么A的成员函数就可以访问B的私有成员
class CCar { private : int price; friend class CDiver ; }; class CDiver { public : CCar myCar; void ModifyCar () { myCar.price += 1000 ; } }
友元类之间的关系不能传递,也无法继承,也就是如果A是B的友元,B是C的友元,那么不能说A是C的友元。
this指针
this指针的作用是指向成员函数所作用的对象。非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针。
class Complex { public : double real, imag; void Print () {cout <<real<<"," <<imag;} Complex(double r, double i):real(r), imag(i){} Complex AddOne () { this ->real++; this ->Print(); return *this ; } };
使用时:
int main () { Complex c1(1, 1), c2(0, 0); c2 = c1.AddOne(); return 0 ; }
c++编译时相当于需要把它转换成c语言,转换后的代码为:
struct Complex { double real; double imag; } void Print (struct Complex *this ) { cout <<this ->real<<"," <<this ->imag; } void Complex (struct Complex *this , double r, double , i) { this ->real = r; this ->imag = i; } struct Complex AddOne (struct Complex *this ) { this ->real++; this ->Print(this ); return *this ; } int main () { struct Complex complex1 ; Complex(& complex1, 1 , 1 ); struct Complex complex2 ; Complex(& complex2, 0 , 0 ); complex2 = AddOne(& complex1); Print(& complex2); return 0 ; }
在程序中c2的实部为2,虚部为1,输出结果为
this指针作用
在编译时,如果对象是空,即this指针作用的对象为NULL,
class A { int i; public : void Hello () { cout <<"Hello" <<endl ; } }; int main () { A *p = NULL ; p->Hello(); }
在编译时,如果对象是空,即this指针作用的对象为NULL,程序仍然会执行第10行代码p->Hello()
程序,因为在编译时,翻译为:
void Hello (A * this ) { cout <<"Hello" <<end } int main () { A *p = NULL ; p->Hello(p); }
在这种情况下程序不会产生错误。
在下面的情况下,程序会出错:
class A { int i; public : void Hello () { cout <<i<<"Hello" <<endl ; } }; int main () { A *p = NULL ; p->Hello(); }
此时,编译翻译为c语言时,变为:
void Hello (A * this ) { cout <<this ->i<<"Hello" <<endl ; } int main () { A *p = NULL ; p->Hello(p); }
这里this是个空指针,因此this->i
这句会编译错误。
this指针和静态成员函数
静态成员函数中不能使用this指针,因为静态成员函数不具体作用于某个对象,因此在翻译时,静态成员函数的真实的参数个数就是程序中写出的参数个数。
常量及常引用
常量对象
如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加const关键字。
如:
class Demo { private : int value; public : void SetValue () {} }; const Demo Obj;
obj初始化完成之后就无法再修改其值。
常量成员函数
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数。
如:
class Sample { public : int value; void GetValue () const ; void func () { }; Sample() { } }; void Sample::GetValue() const { value = 0 ; func(); }
常量成员函数执行期间不应修改其所作用的对象。因此,在常量成员函数中不能修改成员变量的值(静态成员变量除外),也不能调用同类的非常量成员函数(静态成员函数除外)。
在main函数中,常量对象用法:
int main () { const Sample sample; sample.value = 100 ; sample.func(); sample.GetValue(); return 0 ; }
两个成员函数,名字和参数表都一样,但是一个是const,一个不是,算重载。
如:
class CTest { private : int n; public : CTest(){n=1 ;} int GetValue () const {return n;} int GetValue () {return 2 * n;} }; int main () { const CTest objTest1; CTest objTest2; cout <<objTest1.GetValue()<<"," <<objTest2.GetValue(); return 0 ; }
输出结果为:
常引用
引用前面可以加const关键字,称为常引用。不能通过常引用,修改其引用的变量。
如:
const int & r = n;r = 6 ; n = 4 ;
常引用经常被用来作为函数的参数,因为在写函数的时候,若把对象作为函数参数,生成这个参数对象需要调用复制构造函数,增加了时间和空间的开销。因此,使用对象的引用作为参数,节省开销。
对象引用作为函数参数有一定的风险性,若函数中不小心修改了形参的值,那么实参也会发生改变,如果不想让实参发生变化,可以将形参写为const Object & o
可以确保不会出现无意中更改o值的语句。
测验
以下关于 this 指针的说法中不正确的是:
以下程序,哪个是不正确的?
int main () { class A { int v; }; A a; a.v = 3 ; return 0 ; }
int main () { class A { public : int v; A * p; }; A a; a.p = & a; return 0 ; }
int main () { class A { public : int v; }; A * p = new A; p->v = 4 ; delete p; return 0 ; }
int main () { class A { public : int v; A * p; }; A a; a.p = new A; delete a.p; return 0 ; }
编程作业
程序填空
下面程序输出结果是:
填空:
#include <iostream> using namespace std ;class A { public : int val; A(int n=0 ){val = n;} A & GetObj () {return *this ;} }; int main () { A a; cout <<a.val<<endl ; a.GetObj() = 5 ; cout <<a.val<<endl ; }
空缺处代码为:
A(int n=0 ){ val = n; } A & GetObj () { return *this ; }
下面程序的输出是:
请补足Sample类的成员函数。不能增加成员变量。
#include <iostream> using namespace std ;class Sample { public : int v; Sample(int n):v(n) { } }; int main () { Sample a (5 ) ; Sample b = a; cout << b.v; return 0 ; }
空缺处代码为:
Sample(Sample & o){ v = o.v * 2 ; }
下面程序的输出结果是:
请填空:
#include <iostream> using namespace std ;class Base { public : int k; Base(int n):k(n) { } }; class Big { public : int v; Base b; }; int main () { Big a1 (5 ) ; Big a2 = a1; cout << a1.v << "," << a1.b.k << endl ; cout << a2.v << "," << a2.b.k << endl ; return 0 ; }
空缺处代码为:
程序设计
魔兽世界之一:备战
描述
魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市。
红司令部,City 1,City 2,……,City n,蓝司令部
两军的司令部都会制造武士。武士一共有 dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值、攻击力这三种属性。
双方的武士编号都是从1开始计算。红方制造出来的第n个武士,编号就是n。同样,蓝方制造出来的第n个武士,编号也是n。武士在刚降生的时候有一个生命值。在每个整点,双方的司令部中各有一个武士降生。
红方司令部按照iceman、lion、wolf、ninja、dragon的顺序循环制造武士。
蓝方司令部按照lion、dragon、ninja、iceman、wolf的顺序循环制造武士。
制造武士需要生命元。
制造一个初始生命值为m的武士,司令部中的生命元就要减少m个。
如果司令部中的生命元不足以制造某个按顺序应该制造的武士,那么司令部就试图制造下一个。如果所有武士都不能制造了,则司令部停止制造武士。
给定一个时间,和双方司令部的初始生命元数目,要求你将从0点0分开始到双方司令部停止制造武士为止的所有事件按顺序输出。
一共有两种事件,其对应的输出样例如下:
武士降生
输出样例: 004 blue lion 5 born with strength 5,2 lion in blue headquarter
表示在4点整,编号为5的蓝魔lion武士降生,它降生时生命值为5,降生后蓝魔司令部里共有2个lion武士。(为简单起见,不考虑单词的复数形式)注意,每制造出一个新的武士,都要输出此时司令部里共有多少个该种武士。
司令部停止制造武士
输出样例: 010 red headquarter stops making warriors
表示在10点整,红方司令部停止制造武士
输出事件时:
首先按时间顺序输出;
同一时间发生的事件,先输出红司令部的,再输出蓝司令部的。
输入
第一行是一个整数,代表测试数据组数。
每组测试数据共两行。
第一行:一个整数M。其含义为, 每个司令部一开始都有M个生命元( 1 <= M <= 10000)。
第二行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的初始生命值。它们都大于0小于等于10000。
例:
输出
对每组测试数据,要求输出从0时0分开始,到双方司令部都停止制造武士为止的所有事件。
对每组测试数据,首先输出"Case:n" n是测试数据的编号,从1开始 。
接下来按恰当的顺序和格式输出所有事件。每个事件都以事件发生的时间开头,时间以小时为单位,有三位。
例:
Case:1 000 red iceman 1 born with strength 5,1 iceman in red headquarter 000 blue lion 1 born with strength 6,1 lion in blue headquarter 001 red lion 2 born with strength 6,1 lion in red headquarter 001 blue dragon 2 born with strength 3,1 dragon in blue headquarter 002 red wolf 3 born with strength 7,1 wolf in red headquarter 002 blue ninja 3 born with strength 4,1 ninja in blue headquarter 003 red headquarter stops making warriors 003 blue iceman 4 born with strength 5,1 iceman in blue headquarter 004 blue headquarter stops making warriors
代码
class Warrior {public : string color; int HP; Warrior(string c, int i){ color = c; HP = HPs[i] } }; class Dragon : public Warrior{public : Dragon(string color):warrior(color, 0 ){} }; class Ninja : public Warrior{public : Ninja(string color):warrior(color, 1 ){} }; class Iceman : public Warrior{public : Iceman(string color):warrior(color, 2 ){} }; class Lion : public Warrior{public : Lion(string color):warrior(color, 3 ){} }; class Wolf : public Warrior{public : Wolf(string color):warrior(color, 4 ){} }; class Headquart {private : int power; string color; int numberOfWarriors; bool carryOn; int each[5 ]; int current; int selectType; public : Headquart(int p, string c){ color = c; power = p; carrayOn = true ; numberOfWarriors = 0 ; current = 0 ; for (int i=0 ; i<5 ; i++){ each[i] = 0 ; } } bool getCarrayOn () { return carrayOn; } bool create (string c) { cout <<c; int HPOrder[5 ]; for (int i=0 ; i<5 ; i++){ if ( c=="red" ) HPOrder[i] = HPs[redOrder[i]]; if (c=="blue" ) HPOrder[i] = HPs[blueOrder[i]]; }; if (power < minHP){ cout <<"headquarter stops making warriors" <<endl ; carryOn = false ; return false ; } while (power >= minHP){ if (power >= HPOrder[current]) break ; if (current == 4 ) current = 0 ; else current++; } if (c == "red" ) select = redOrder[current]; if (c == "blue" ) select = blueOrder[current]; string warriors[5 ] = { " dragon " ," ninja " ," iceman " ," lion " ," wolf " }; switch (select){ case 0 : new Dragon(c); each[0 ]++; power = power - HPs[0 ]; } return true ; } }