C语言程序设计(郑莉)课后习题答案_c语言课后习题及答案
C语言程序设计(郑莉)课后习题答案由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“c语言课后习题及答案”。
C++语言程序设计(清华大学郑莉)课后习题答案
第 一 章 概述
1-1 简述计算机程序设计语言的发展历程。
解:
迄今为止计算机程序设计语言的发展经历了机器语言、汇编语言、高级语言等阶段,C++语言是一种面向对象的编程语言,也属于高级语言。
1-2 面向对象的编程语言有哪些特点?
解:
面向对象的编程语言与以往各种编程语言有根本的不同,它设计的出发点就是为了能更直接的描述客观世界中存在的事物以及它们之间的关系。面向对象的编程语言将客观事物看作具有属性和行为的对象,通过抽象找出同一类对象的共同属性(静态特征)和行为(动态特征),形成类。通过类的继承与多态可以很方便地实现代码重用,大大缩短了软件开发周期,并使得软件风格统一。因此,面向对象的编程语言使程序能够比较直接地反问题域的本来面目,软件开发人员能够利用人类认识事物所采用的一般思维方法来进行软件开发。C++语言是目前应用最广的面向对象的编程语言。
1-3 什么是结构化程序设计方法?这种方法有哪些优点和缺点?
解:
结构化程序设计的思路是:自顶向下、逐步求精;其程序结构是按功能划分为若干个基本模块;各模块之间的关系尽可能简单,在功能上相对独立;每一模块内部均是由顺序、选择和循环三种基本结构组成;其模块化实现的具体方法是使用子程序。结构化程序设计由于采用了模块分解与功能抽象,自顶向下、分而治之的方法,从而有效地将一个较复杂的程序系统设计任务分解成许多易于控制和处理的子任务,便于开发和维护。虽然结构化程序设计方法具有很多的优点,但它仍是一种面向过程的程序设计方法,它把数据和处理数据的过程分离为相互独立的实体。当数据结构改变时,所有相关的处理过程都要进行相应的修改,每一种相对于老问题的新方法都要带来额外的开销,程序的可重用性差。
由于图形用户界面的应用,程序运行由顺序运行演变为事件驱动,使得软件使用起来越来越方便,但开发起来却越来越困难,对这种软件的功能很难用过程来描述和实现,使用面向过程的方法来开发和维护都将非常困难。
1-4 什么是对象?什么是面向对象方法?这种方法有哪些特点?
解:
从一般意义上讲,对象是现实世界中一个实际存在的事物,它可以是有形的,也可以是无形的。对象是构成世界的一个独立单位,它具有自己的静态特征和动态特征。面向对象方法中的对象,是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位,由一组属性和一组行为构成。面向对象的方法将数据及对数据的操作方法放在一起,作为一个相互依存、不可分离的整体--对象。对同类型对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口,与外界发生关系,对象与对象之间通过消息进行通讯。这样,程序模块间的关系更为简单,程序模块的独立性、数据的安全性就有了良好的保障。通过实现继承与多态性,还可以大大提高程序的可重用性,使得软件的开发和维护都更为方便。
面向对象方法所强调的基本原则,就是直接面对客观存在的事物来进行软件开发,将人们在日常生活中习惯的思维方式和表达方式应用在软件开发中,使软件开发从过分专业化的方法、规则和技巧中回到客观世界,回到人们通常的思维。
1-5 什么叫做封装?
解:
封装是面向对象方法的一个重要原则,就是把对象的属性和服务结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。
1-6 面向对象的软件工程包括哪些主要内容?
解:
面向对象的软件工程是面向对象方法在软件工程领域的全面应用,它包括面向对象的分析(OOA)、面向对象的设计(OOD)、面向对象的编程(OOP)、面向对象的测试(OOT)和面向对象的软件维护(OOSM)等主要内容。
1-7 简述计算机内部的信息可分为几类?
解:
计算机内部的信息可以分成控制信息和数据信息二大类;控制信息可分为指令和控制字两类;数据信息可分为数值信息和非数值信息两类。
1-8 什么叫二进制?使用二进制有何优点和缺点?
解:
二进制是基数为2,每位的权是以2 为底的幂的进制,遵循逢二进一原则,基本符号为0和1。采用二进制码表示信息,有如下几个优点:1.易于物理实现;2.二进制数运算简单;3.机器可靠性高;4.通用性强。其缺点是它表示数的容量较小,表示同一个数,二进制较其他进制需要更多的位数。
1-9 请将以下十进制数值转换为二进制和十六进制补码:(1)2(2)9(3)93(4)-32(5)65535(6)-1
解:
(1)(2)10 =(10)2 =(2)16(2)(9)10 =(1001)2 =(9)16(3)(93)10 =(1011101)2 =(5D)16(4)(-32)10 =(11100000)2 =(E0)16(5)(65535)10 =(11111111 11111111)2 =(FFFF)16(6)(-1)10 =(11111111 11111111)2 =(FFFF)16
1-10 请将以下数值转换为十进制:
(1)(1010)2(2)(10001111)2(3)(01011111 11000011)2(4)(7F)16(5)(2D3E)16(6)(F10E)16
解:
(1)(1010)2 =(10)10(2)(10001111)2 =(143)10(3)(01011111 11000011)2 =(24515)10
(4)(7F)16 =(127)10(5)(2D3E)16 =(11582)10(6)(F10E)16 =(61710)10
1-11 简要比较原码、反码、补码等几种编码方法。
解:
原码:将符号位数字化为 0 或 1,数的绝对值与符号一起编码,即所谓“符号──绝对值表示”的编码。正数的反码和补码与原码表示相同。负数的反码与原码有如下关系:
符号位相同(仍用1表示),其余各位取反(0变1,1变0)。补码由该数反码的最末位加1求得。
第 二 章 C++简单程序设计
2-1 C++语言有那些主要特点和优点?
解:
C++语言的主要特点表现在两个方面,一是全面兼容C,二是支持面向对象的方法。C++是一个更好的C,它保持了C的简洁、高效、接近汇编语言、具有良好的可读性和可移植性等特点,对C的类型系统进行了改革和扩充,因此C++比C更安全,C++的编译系统能检查出更多的类型错误。C++语言最重要的特点是支持面向对象。
2-2 下列标识符哪些是合法的?
Program,-page,_lock,test2,3in1,@mail,A_B_C_D
解:
Program,_lock,test2,A_B_C_D是合法的标识符,其它的不是。
2-3 例2.1中每条语句的作用是什么? #include void main(void){
cout
cout
解:
#include //指示编译器将文件iostream.h中的代码
//嵌入到该程序中该指令所在的地方
void main()//主函数名,void 表示函数没有返回值 { //函数体标志
cout
cout
2-4 使用关键字const而不是#define语句的好处有哪些?
解:
const定义的常量是有类型的,所以在使用它们时编译器可以查错;而且,这些变量在调试时仍然是可见的。
2-5 请写出C++语句声明一个常量PI,值为3.1416;再声明一个浮点型变量a,把PI的值赋给a。
解:
const float PI = 3.1416;float a = PI;
2-6 在下面的枚举类型中,Blue的值是多少?
enum COLOR { WHITE,BLACK = 100,RED,BLUE,GREEN = 300 };
解: Blue = 102
2-7 注释有什么作用?C++中有哪几种注释的方法?他们之间有什么区别?
解:
注释在程序中的作用是对程序进行注解和说明,以便于阅读。编译系统在对源程序进行编译时不理会注释部分,因此注释对于程序的功能实现不起任何作用。而且由于编译时忽略注释部分,所以注释内容不会增加最终产生的可执行程序的大小。适当地使用注释,能够提高程序的可读性。在C++中,有两种给出注释的方法:一种是延用C语言方法,使用“/*”和“*/”括起注释文字。另一种方法是使用“//”,从“//”开始,直到它所在行的行尾,所有字符都被作为注释处理。
2-8 什么叫做表达式?x = 5 + 7是一个表达式吗?它的值是多少?
解:
任何一个用于计算值的公式都可称为表达式。x = 5 + 7是一个表达式,它的值为12。
2-9 下列表达式的值是多少? 1.201 / 4 2.201 % 4 3.201 / 4.0
解: 1. 50 2. 1 3. 50.25
2-10 执行完下列语句后,a、b、c三个变量的值为多少? a = 30;b = a++;c = ++a;
解:
a:32 ; b:30 ; c:32;
2-11 在一个for循环中,可以初始化多个变量吗?如何实现?
解:
在for循环设置条件的第一个“;”前,用,分隔不同的赋值表达式。例如:
for(x = 0,y = 10;x
2-12 执行完下列语句后,n的值为多少? int n;for(n = 0;n
解: n的值为100
2-13 写一条for语句,计数条件为n从100到200,步长为2;然后用while和do„while语句完成同样的循环。
解: for循环:
for(int n = 100;n
while循环: int x = 100;while(n
do„while循环: int n = 100;do { n += 2;} while(n
2-14 if(x = 3)和 if(x = = 3)这两条语句的差别是什么?
解:
语句if(x = 3)把3赋给x,赋值表达式的值为true,作为if语句的条件;语句if(x == 3)首先判断x的值是否为3,若相等条件表达式的值为ture,否则为false。
2-15 什么叫做作用域?什么叫做局部变量?什么叫做全局变量,如何使用全局变量?
解:
作用域是一个标识符在程序正文中有效的区域。局部变量,一般来讲就是具有块作用域的变量;全局变量,就是具有文件作用域的变量。
2-16 已知x、y两个变量,写一条简单的if语句,把较小的的值赋给原本值较大的变量。
解: if(x > y)x = y;
else // y > x || y == x y = x;
2-17 修改下面这个程序中的错误,改正后它的运行结果是什么?
#include void main()int i int j;
i = 10;/* 给i赋值 j = 20;/* 给j赋值 */
cout
解: 改正:
#include int main(){ int i;int j;
i = 10;// 给i赋值 j = 20;/* 给j赋值 */
cout
程序运行输出: i + j = 30
2-18 编写一个程序,运行时提示输入一个数字,再把这个数字显示出来。
解: 源程序:
#include
int main(){ int i;cout > i;cout
2-19 C++有哪几种数据类型?简述其值域。编程显示你使用的计算机中的各种数据类型的字节数。
解: 源程序:
#include
int main(){ cout
The size of an int is: 4 bytes.The size of a short int is: 2 bytes.The size of a long int is: 4 bytes.The size of a char is: 1 bytes.The size of a float is: 4 bytes.The size of a double is: 8 bytes.2-20 打印ASCII码为32~127的字符。
解:
#include int main(){
for(int i = 32;i
程序运行输出:
!“#$%G'()*+,./0123456789:;?@ABCDEFGHIJKLMNOP_QRSTUVWXYZ[]^'abcdefghijklmnopqrstuvwxyz~s
2-21 运行下面的程序,观察其输出,与你的设想是否相同? #include int main(){
unsigned int x;unsigned int y = 100;unsigned int z = 50;x= yy;
cout
解:
程序运行输出: Difference is: 50
Now difference is: 4294967246
注意,第二行的输出并非-50,注意x、y、z的数据类型。
2-22 运行下面的程序,观察其输出,体会i++与++i的差别。#include int main(){int myAge = 39;// initialize two integers int yourAge = 39;cout
auto存储类型:采用堆栈方式分配内存空间,属于一时性存储,其存储空间可以被若干变量多次覆盖使用; register存储类型:存放在通用寄存器中;
extern存储类型:在所有函数和程序段中都可引用; static存储类型:在内存中是以固定地址存放的,在整个程序cout
解:
程序运行输出: I am 39 years old You are 39 years old One year paes I am 40 years old You are 40 years old Another year paes I am 40 years old You are 41 years old Let's print it again I am 41 years old You are 41 years old
2-23 什么叫常量?什么叫变量?
解:
所谓常量是指在程序运行的整个过程中其值始终不可改变的量,除了用文字表示常量外,也可以为常量命名,这就是符号常量;在程序的执行过程中其值可以变化的量称为变量,变量是需要用名字来标识的。
2-24 变量有哪几种存储类型?
解:
运行期间都有效。
2-25 写出下列表达式的值: 1.2
3.!(3 > 5)||(6 解: 1.true 2.false 3.true 2-26 若a = 1,b = 2,c = 3,下列各式的结果是什么? 1.a | b32)* 5/9;在主程序中提示用户输入一个华氏温度,转化后输出相应的摄氏温度。 解: 源程序见”实验指导“部分实验三 3-9 编写函数判断一个数是否是质数,在主程序中实现输入、输出。 解: #include #include int prime(int i);//判一个数是否是质数的函数 void main(){ int i; cout > i;if(prime(i)) cout cout int prime(int i){int j,k,flag;flag = 1;k = sqrt(i);for(j = 2;j 3-10 编写函数求两个整数的最大公约数和最小公倍数。 解: 源程序: #include #include int fn1(int i,int j);//求最大公约数的函数 void main(){ int i,j,x,y;cout > i;cout > j; x = fn1(i,j);y = i * j / x;cout int fn1(int i, int j){ int temp;if(i { temp = i;i = j;j = i;} while(j!= 0){ temp = i % j;i = j;j = temp;} return i;} 程序运行输出: 请输入一个正整数:120 请输入另一个正整数:72 120和72的最大公约数是:24 120和72的最小公倍数是:360 3-11 什么叫作嵌套调用?什么叫作递归调用? 解: 函数允许嵌套调用,如果函数1调用了函数2,函数2再调用函数3,便形成了函数的嵌套调用。 函数可以直接或间接地调用自身,称为递归调用。 3-12 在主程序中提示输入整数n,编写函数用递归的方法求1 + 2 + „ + n的值。 解: #include #include int fn1(int i); void main(){ int i; cout > i; cout int fn1(int i){ if(i == 1)return 1;else return i + fn1(i-1);} 程序运行输出: 请输入一个正整数:100 从1累加到100的和为:5050 3-13 编写递归函数GetPower(int x,int y)计算x的y次幂,在主程序中实现输入输出。 解: 源程序: #include long GetPower(int x,int y);int main(){ int number,power;long answer;cout > number;cout > power;answer = GetPower(number,power);cout long GetPower(int x,int y){ if(y == 1)return x;else return(x * GetPower(x,y-1));} 程序运行输出: Enter a number: 3 To what power? 4 3 to the 4th power is 81 3-14 用递归的方法编写函数求Fibonacci 级数,公式为fib(n) = fib(n-1)+ fib(n-2),n>2; fib(1)= fib(2)= 1;观察递归调用的过程。 解: 源程序见”实验指导“部分实验三 3-15 用递归的方法编写函数求n阶勒让德多项式的值,在主程序中实现输入、输出; 解: #include float p(int n, int x); void main(){ int n,x; cout > n; cout > x; cout cout float p(int n, int x){ if(n == 0)return 1;else if(n == 1)return x;else return((2*n-1)*x*p(n-1,x)itsBottom;return(Width * Height);} int main(){ Rectangle MyRectangle(100, 20, 50, 80); int Area = MyRectangle.GetArea(); cout 4-10 设计一个用于人事管理的People(人员)类。考虑到通用性,这里只抽象出所有类型人员都具有的属性:number(编号)、sex(性别)、birthday(出生日期)、id(身份证号)等等。其中”出生日期“定义为一个”日期“类内嵌子对象。用成员函数实现对人员信息的录入和显示。要求包括:构造函数和析构函数、拷贝构造函数、内联成员函数、带缺省形参值的成员函数、聚集。 解: 本题用作实验四的选做题,因此不给出答案。 4-11 定义一个矩形类,有长、宽两个属性,有成员函数计算矩形的面积 解: #include cla Rectangle { public: Rectangle(float len, float width){ Length = len;Width = width;} ~Rectangle(){}; float GetArea(){ return Length * Width;} float GetLength(){ return Length;} float GetWidth(){ return Width;} private: float Length;float Width;}; void main(){ float length, width; cout > length; cout > width; Rectangle r(length, width); cout 程序运行输出: 请输入矩形的长度:5 请输入矩形的宽度:4 长为5宽为4的矩形的面积为:20 4-12 定义一个”数据类型“ datatype类,能处理包含字符型、整型、浮点型三种类型的数据,给出其构造函数。解: #include cla datatype{ enum{ character, integer, floating_point } vartype;union { char c;int i;float f;};public: datatype(char ch){ vartype = character;c = ch;} datatype(int ii){ vartype = integer;i = ii;} datatype(float ff){ vartype = floating_point;f = ff;} void print();}; void datatype::print(){ switch(vartype){ case character: cout void main(){ datatype A('c'), B(12), C(1.44F); A.print();B.print();C.print();} 程序运行输出: 字符型: c 整型: 12 浮点型: 1.44 4-13 定义一个Circle类,有数据成员半径Radius,成员函数GetArea(),计算圆的面积,构造一个Circle的对象进行测试。 解: #include cla Circle { public: Circle(float radius){ Radius = radius;} ~Circle(){} float GetArea(){ return 3.14 * Radius * Radius;} private: float Radius;}; void main(){ float radius; cout > radius;Circle p(radius); cout 程序运行输出: 请输入圆的半径:5 半径为5的圆的面积为:78.5 4-14 定义一个tree类,有成员ages,成员函数grow(int years)对ages加上years,age()显示tree对象的ages的值。解: #include cla Tree { int ages;public: Tree(int n=0);~Tree();void grow(int years);void age();}; Tree::Tree(int n){ ages = n;} Tree::~Tree(){ age();} void Tree::grow(int years){ ages += years;} void Tree::age(){ cout void main(){ Tree t(12); t.age();t.grow(4);} 程序运行输出: 这棵树的年龄为12 这棵树的年龄为16 第 五 章 C++程序的基本结构 5-1 什么叫做作用域?有哪几种类型的作用域? 解: 作用域讨论的是标识符的有效范围,作用域是一个标识符在程序正文中有效的区域。C++的作用域分为函数原形作用域、块作用域(局部作用域)、类作用域和文件作用域.5-2 什么叫做可见性?可见性的一般规则是什么? 解: 可见性是标识符是否可以引用的问题; 可见性的一般规则是:标识符要声明在前,引用在后,在同一作用域中,不能声明同名的标识符。对于在不同的作用域声明的标识符,遵循的原则是:若有两个或多个具有包含关系的作用域,外层声明的标识符如果在内层没有声明同名标识符时仍可见,如果内层声明了同名标识符则外层标识符不可见。 5-3 下面的程序的运行结果是什么,实际运行一下,看看与你的设想有何不同。#include void myFunction(); int x = 5,y = 7;int main(){ cout cout void myFunction(){ int y = 10; cout 解: 程序运行输出: x from main: 5 y from main: 7 x from myFunction: 5 y from myFunction: 10 Back from myFunction! x from main: 5 y from main: 7 5-4 假设有两个无关系的类Engine和Fuel,使用时,怎样允许Fuel成员访问Engine中的私有和保护的成员? 解: 源程序: cla fuel;cla engine { friend cla fuel;private;int powerlevel;public;engine(){ powerLevel = 0;} void engine_fn(fuel &f);};cla fuel { friend cla engine;private;int fuelLevel;public: fuel(){ fuelLevel = 0;} void fuel_fn(engine &e);}; 5-5 什么叫做静态数据成员?它有何特点? 解: 类的静态数据成员是类的数据成员的一种特例,采用static关键字来声明。对于类的普通数据成员,每一个类的对象都拥 有一个拷贝,就是说每个对象的同名数据成员可以分别存储不同的数值,这也是保证对象拥有自身区别于其它对象的特征的需要,但是静态数据成员,每个类只要一个拷贝,由所有该类的对象共同维护和使用,这个共同维护、使用也就实现了同一类的不同对象之间的数据共享。 5-6 什么叫做静态函数成员?它有何特点? 解: 使用static关键字声明的函数成员是静态的,静态函数成员属于整个类,同一个类的所有对象共同维护,为这些对象所共享。静态函数成员具有以下两个方面的好处,一是由于静态成员函数只能直接访问同一个类的静态数据成员,可以保证不会对该类的其余数据成员造成负面影响;二是同一个类只维护一个静态函数成员的拷贝,节约了系统的开销,提高程序的运行效率。 5-7 定义一个Cat类,拥有静态数据成员HowManyCats,记录Cat的个体数目;静态成员函数GetHowMany(),存取HowManyCats。设计程序测试这个类,体会静态数据成员和静态成员函数的用法。 解: 源程序: #include cla Cat { public: Cat(int age):itsAge(age){HowManyCats++;} virtual ~Cat(){ HowManyCats--;} virtual int GetAge(){ return itsAge;} virtual void SetAge(int age){ itsAge = age;} static int GetHowMany(){ return HowManyCats;} private: int itsAge; static int HowManyCats;}; int Cat::HowManyCats = 0; void TelepathicFunction(); int main(){const int MaxCats = 5;Cat *CatHouse[MaxCats];int i;for(i = 0;i for(i = 0;i void TelepathicFunction(){ cout 程序运行输出: There are 1 cats alive!There are 2 cats alive!There are 3 cats alive!There are 4 cats alive!There are 5 cats alive!There are 4 cats alive!There are 3 cats alive!There are 2 cats alive!There are 1 cats alive!There are 0 cats alive! 5-8 什么叫做友元函数?什么叫做友元类? 解: 友元函数是使用friend关键字声明的函数,它可以访问相应类的保护成员和私有成员。友元类是使用friend关键字声明的类,它的所有成员函数都是相应类的友元函数。 5-9 如果类A是类B的友元,类B是类C的友元,类D是类A的派生类,那么类B是类A的友元吗?类C是类A的友元吗?类D是类B的友元吗? 解: 类B不是类A的友元,友元关系不具有交换性; 类C不是类A的友元,友元关系不具有传递性; 类D不是类B的友元,友元关系不能被继承。 5-10 静态成员变量可以为私有的吗?声明一个私有的静态整型成员变量。 解: 可以,例如: private: static int a; 5-11 在一个文件中定义一个全局变量n,主函数main(),在另一个文件中定义函数fn1(),在main()中对n赋值,再调用fn1(),在fn1()中也对n赋值,显示n最后的值。 解: #include #include ”fn1.h“ int n; void main(){ n = 20;fn1(); cout // fn1.h文件 extern int n; void fn1(){ n=30;} 程序运行输出: n的值为30 5-12 在函数fn1()中定义一个静态变量n,fn1()中对n的值加1,在主函数中,调用fn1()十次,显示n的值。 解: #include void fn1(){ static int n = 0;n++;cout void main(){ for(int i = 0;i 程序运行输出: n的值为1 n的值为2 n的值为3 n的值为4 n的值为5 n的值为6 n的值为7 n的值为8 n的值为9 n的值为10 5-13 定义类X、Y、Z,函数h(X*),满足:类X有私有成员i,Y的成员函数g(X*)是X的友元函数,实现对X的成员i加1,类Z是类X的友元类,其成员函数f(X*)实现对X的成员i加5,函数h(X*)是X的友元函数,实现对X的成员i加10。在一个文件中定义和实现类,在另一个文件中实现main()函数。 解: #include ”my_x_y_z.h“ void main(){ X x;Z z;z.f(&x);} // my_x_y_z.h文件 #ifndef MY_X_Y_Z_H cla X;cla Y { void g(X*);}; cla X { private: int i;public: X(){i=0;} friend void h(X*);friend void Y::g(X*);friend cla Z;}; void h(X* x){ x->i =+10;} void Y::g(X* x){ x->i ++;} cla Z { public: void f(X* x){ x->i += 5;} }; #endif // MY_X_Y_Z_H 程序运行输出:无 5-14 定义Boat与Car两个类,二者都有weight属性,定义二者的一个友元函数totalWeight(),计算二者的重量和。 解: 源程序: #include cla Boat;cla Car { private: int weight;public:Car(int j){weight = j;} friend int totalWeight(Car &aCar,Boat &aBoat);}; cla Boat { private: int weight;public: Boat(int j){weight = j;} friend int totalWeight(Car &aCar,Boat &aBoat);}; int totalWeight(Car &aCar,Boat &aBoat){ return aCar.weight + aBoat.weight;} void main(){ Car c1(4);Boat b1(5); cout 5-15 如果在类模板的定义中有一个静态数据成员,则在程序运行中会产生多少个相应的静态变量? 解: 这个类模板的每一个实例类都会产生一个相应的静态变量。 第 六 章 数组、指针与字符串 6-1 数组A[10][5][15]一共有多少个元素? 解: 10×5×15 = 750 个元素 1-2 在数组A[20]中第一个元素和最后一个元素是哪一个? 解: 第一个元素是A[0],最后一个元素是A[19]。 6-3 用一条语句定义一个有五个元素的整型数组,并依次赋予1~5的初值。 解: 源程序: int IntegerArray[5] = { 1,2,3,4,5 };或:int IntegerArray[] = { 1,2,3,4,5 }; 6-4 已知有一个数组名叫oneArray,用一条语句求出其元素的个数。 解: 源程序: nArrayLength = sizeof(oneArray)/ sizeof(oneArray[0]); 6-5 用一条语句定义一个有5×3个元素的二维整型数组,并依次赋予1~15的初值。 解: 源程序: int theArray[5][3] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }; 或:int theArray[5][3] = { {1,2,3},{4,5,6},{7,8,9},{10,11,12},{13,14,15} }; 6-6 运算符*和&的作用是什么? 解: *称为指针运算符,是一个一元操作符,表示指针所指向的对象的值;&称为取地址运算符,也是一个一元操作符,是用来得到一个对象的地址。 6-7 什么叫做指针?指针中储存的地址和这个地址中的值有何区别? 解: 指针是一种数据类型,具有指针类型的变量称为指针变量。指针变量存放的是另外一个对象的地址,这个地址中的值就是另一个对象的内容。 6-8 定义一个整型指针,用new语句为其分配包含10个整型元素的地址空间。 解: 源程序: int *pInteger = new int[10]; 6-9 在字符串”Hello,world!”中结束符是什么? 解: 是NULL字符。 6-10 定义一个有五个元素的整型数组,在程序中提示用户输入元素值,最后再在屏幕上显示出来。 解: 源程序: #include int main(){ int myArray[5];int i;for(i=0;i> myArray[i];} for(i = 0;i Value for myArray[0]: 2 Value for myArray[1]: 5 Value for myArray[2]: 7 Value for myArray[3]: 8 Value for myArray[4]: 3 0: 2 1: 5 2: 7 3: 8 4: 3 6-11 引用和指针有何区别?何时只能使用指针而不能使用引用? 解: 引用是一个别名,不能为NULL值,不能被重新分配;指针是一个存放地址的变量。当需要对变量重新赋以另外的地址或赋值为NULL时只能使用指针。 6-12 声明下列指针:float类型变量的指针pFloat,char类型的指针pString和struct customer型的指针prec。 解: float *pfloat;char *pString; struct customer *prec; 6-13 给定float类型的指针fp,写出显示fp所指向的值的输出流语句。 解: cout 6-14 程序中定义一个double类型变量的指针。分别显示指针占了多少字节和指针所指的变量占了多少字节。 解: double *counter; cout 'nSize of addreed value == ” 6-15 const int * p1 和 int * const p2的区别是什么?解: const int * p1 声明了一个指向整型常量的指针p1,因此不能通过指针p1来改变它所指向的整型值;int * const p2声明了一个指针型常量,用于存放整型变量的地址,这个指针一旦初始化后,就不能被重新赋值了。 6-16 定义一个整型变量a,一个整型指针p,一个引用r,通过p把a的值改为10,通过r把a的值改为5 解: void main(){ int a;int *p = &a;int &r = a;*p = 10;r = 5;} 6-17 下列程序有何问题,请仔细体会使用指针时应避免出现这个的问题。 #include int main(){ int *p;*pInt = 9;cout 解: 指针p没有初始化,也就是没有指向某个确定的内存单元,它指向内存中的一个随机地址,给这个随机地址赋值是非常危险的。 6-18 下列程序有何问题,请改正;仔细体会使用指针时应避免出现的这个问题。#include int Fn1();int main(){ int a = Fn1();cout int Fn1(){ int * p = new int(5);return *p;} 解: 此程序中给*p分配的内存没有被释放掉。改正: #include int* Fn1();int main(){ int *a = Fn1(); cout int* Fn1(){ int * p = new int(5);return p;} 6-19 声明一个参数为整型,返回值为长整型的函数指针;声明类A的一个成员函数指针,其参数为整型,返回值长整型。 解: long(* p_fn1)(int);long(A::*p_fn2)(int); 6-20 实现一个名为SimpleCircle的简单圆类,其数据成员int *itsRadius为一个指向其半径值的指针,设计对数据成员的各种操作,给出这个类的完整实现并测试这个类。 解: 源程序: #include cla SimpleCircle {public: SimpleCircle();SimpleCircle(int);SimpleCircle(const SimpleCircle &);~SimpleCircle(){} void SetRadius(int);int GetRadius()const; private: int *itsRadius;}; SimpleCircle::SimpleCircle(){ itsRadius = new int(5);} SimpleCircle::SimpleCircle(int radius){ itsRadius = new int(radius);} SimpleCircle::SimpleCircle(const SimpleCircle & rhs){ int val = rhs.GetRadius();itsRadius = new int(val);} int SimpleCircle::GetRadius()const { return *itsRadius;} int main(){ SimpleCircle CircleOne, CircleTwo(9);cout 6-21 编写一个函数,统计一个英文句子中字母的个数,在主程序中实现输入、输出。 解: 源程序: #include #include int count(char *str){ int i,num=0; for(i=0;str[i];i++){ if((str[i]>='a' && str[i]='A' && str[i] return num;} void main(){ char text[100]; cout cout 程序运行输出: 输入一个英语句子: It is very interesting!这个句子里有19个字母。 6-22 编写函数int index(char *s,char *t),返回字符串t 在字符串s中出现的最左边的位置,如果在s中没有与t匹配的子串,就返回-1。 解: 源程序: #include int index(char *s, char *t){ int i,j,k; for(i = 0;s[i]!= ' ';i++){ for(j = i, k = 0;t[k]!= ' ' && s[j] == t[k];j++, k++);if(t[k] ==' ')return i;} return-1;} void main(){ int n;char str1[20],str2[20];cout > str1;cout > str2;n = index(str1,str2);if(n > 0)cout 输入一个英语单词:abcdefgh 输入另一个英语单词:de de在abcdefghijk中左起第4个位置。 6-23 编写函数reverse(char *s)的倒序递归程序,使字符串s倒序。 解: 源程序: #include #include void reverse(char *s, char *t){ char c;if(s void reverse(char *s) { reverse(s, s + strlen(s)-1);} void main(){ char str1[20]; cout > str1; cout cout 程序运行输出: 输入一个字符串:abcdefghijk 原字符串为:abcdefghijk 倒序反转后为:kjihgfedcba 6-24 设学生人数N=8,提示用户输入N个人的考试成绩,然后计算出平均成绩,显示出来。 解: 源程序: #include #include #define N 8 float grades[N];//存放成绩的数组 void main(){ int i; float total,average; //提示输入成绩 for(i = 0;i cout > grades[i];} total = 0; for(i = 0;i cout Average grade: 79.75 6-25 设计一个字符串类MyString,具有构造函数、析构函数、拷贝构造函数,重载运算符+、=、+=、[],尽可能地完善它,使之能满足各种需要。(运算符重载功能为选做,参见第8章) 解: #include #include cla MyString { public: MyString();MyString(const char *const);MyString(const MyString &);~MyString(); char & operator[](unsigned short offset);char operator[](unsigned short offset)const;MyString operator+(const MyString&);void operator+=(const MyString&);MyString & operator=(const MyString &); unsigned short GetLen()const { return itsLen;} const char * GetMyString()const { return itsMyString;} private: MyString(unsigned short);// private constructor char * itsMyString;unsigned short itsLen;}; MyString::MyString() { itsMyString = new char[1];itsMyString[0] = ' ';itsLen=0;} MyString::MyString(unsigned short len){ itsMyString = new char[len+1]; for(unsigned short i = 0;i MyString::MyString(const char * const cMyString){ itsLen = strlen(cMyString);itsMyString = new char[itsLen+1]; for(unsigned short i = 0;i MyString::MyString(const MyString & rhs){ itsLen=rhs.GetLen(); itsMyString = new char[itsLen+1];for(unsigned short i = 0;i MyString::~MyString(){ delete [] itsMyString;itsLen = 0;} MyString& MyString::operator=(const MyString & rhs){ if(this == &rhs)return *this; delete [] itsMyString;itsLen=rhs.GetLen(); itsMyString = new char[itsLen+1];for(unsigned short i = 0;i return *this;} char & MyString::operator[](unsigned short offset){ if(offset > itsLen)return itsMyString[itsLen-1];else return itsMyString[offset];} char MyString::operator[](unsigned short offset)const { if(offset > itsLen)return itsMyString[itsLen-1];else return itsMyString[offset];} MyString MyString::operator+(const MyString& rhs){ unsigned short totalLen = itsLen + rhs.GetLen();MyString temp(totalLen);for(unsigned short i = 0;i void MyString::operator+=(const MyString& rhs){ unsigned short rhsLen = rhs.GetLen();unsigned short totalLen = itsLen + rhsLen;MyString temp(totalLen);for(unsigned short i = 0;i int main(){ MyString s1(“initial test”);cout char * temp = “Hello World”;s1 = temp; cout char tempTwo[20]; strcpy(tempTwo,“;nice to be here!”);s1 += tempTwo; cout cout cout cout MyString s2(“ Another myString”);MyString s3;s3 = s1+s2; cout MyString s4; s4 = “Why does this work?”; cout 程序运行输出: S1: initial test S1: Hello World tempTwo:;nice to be here!S1: Hello World;nice to be here!S1[4]: o S1: Hellx World;nice to be here!S1[999]:! S3: Hellx World;nice to be here!Another myString S4: Why does this work? 6-26 编写一个3×3矩阵转置的函数,在main()函数中输入数据。 解: #include void move(int matrix[3][3]){ int i, j, k;for(i=0;i void main(){ int i, j;int data[3][3];cout > data[i][j];} cout 程序运行输出: 输入矩阵的元素 第1行第1个元素为:1 第1行第2个元素为:2 第1行第3个元素为:3 第2行第1个元素为:4 第2行第2个元素为:5 第2行第3个元素为:6 第3行第1个元素为:7 第3行第2个元素为:8 第3行第3个元素为:9 输入的矩阵的为: 1 2 3 4 5 6 7 8 9 转置后的矩阵的为: 1 4 7 2 5 8 3 6 9 6-27 编写一个矩阵转置的函数,矩阵的维数在程序中由用户输入。 解: #include void move(int *matrix ,int n){ int i, j, k;for(i=0;i k = *(matrix + i*n + j); *(matrix + i*n + j)= *(matrix + j*n + i);*(matrix + j*n + i)= k;} } void main(){ int n, i, j;int *p; cout > n; p = new int[n*n]; cout cout > p[i*n + j];}cout 6-28 定义一个Employee类,其中包括表示姓名、街道地址、城市和邮编等属性,包括chage_name()和display()等函数;display()使用cout语句显示姓名、街道地址、城市和邮编等属性,函数change_name()改变对象的姓名属性,实现并测试这个类。 解: 源程序: #include #include cla Employee { private: char name[30];char street[30];char city[18];char zip[6];public: Employee(char *n, char *str, char *ct, char *z);void change_name(char *n);void display();}; Employee::Employee(char *n,char *str,char *ct, char *z){ strcpy(name, n);strcpy(street, str);strcpy(city, ct);strcpy(zip, z);} void Employee::change_name(char *n){ strcpy(name, n);} void Employee::display(){ cout void main(void){ Employee e1(“张三”,“平安大街3号”, “北京”, “100000”);e1.display();cout e1.change_name(“李四”);e1.display();cout 程序运行输出: 张三 平安大街3号 北京 100000 李四 平安大街3号 北京 100000 第 七 章 继承与派生 7-1 比较类的三种继承方式public公有继承、protected保护继承、private私有继承之间的差别。 解: 不同的继承方式,导致不同访问属性的基类成员在派生类中的访问属性也有所不同: 公有继承,使得基类public(公有)和protected(保护)成员的访问属性在派生类中不变,而基类private(私有)成员不可访问。 私有继承,使得基类public(公有)和protected(保护)成员都以private(私有)成员身份出现在派生类中,而基类private(私有)成员不可访问。 保护继承中,基类public(公有)和protected(保护)成员都以protected(保护)成员身份出现在派生类中,而基类private(私有)成员不可访问。 7-2 派生类构造函数执行的次序是怎样的? 解: 派生类构造函数执行的一般次序为:调用基类构造函数;调用成员对象的构造函数;派生类的构造函数体中的内容。 7-3 如果在派生类B已经重载了基类A的一个成员函数fn1(),没有重载成员函数fn2(),如何调用基类的成员函数fn1()、fn2()? 解: 调用方法为: A::fn1();fn2(); 7-4 什么叫做虚基类?有何作用? 解: 当某类的部分或全部直接基类是从另一个基类派生而来,这些直接基类中,从上一级基类继承来的成员就拥有相同的名称,派生类的对象的这些同名成员在内存中同时拥有多个拷贝,我们可以使用作用域分辨符来唯一标识并分别访问它们。我们也可以将直接基类的共同基类设置为虚基类,这时从不同的路径 继承过来的该类成员在内存中只拥有一个拷贝,这样就解决了同名成员的唯一标识问题。 虚基类的声明是在派生类的定义过程,其语法格式为: cla 派生类名:virtual 继承方式 基类名 上述语句声明基类为派生类的虚基类,在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。声明了虚基类之后,虚基类的成员在进一步派生过程中,和派生类一起维护一个内存数据拷贝。 7-5 定义一个Shape基类,在此基础上派生出Rectangle和Circle,二者都有GetArea()函数计算对象的面积。使用Rectangle类创建一个派生类Square。 解: 源程序: #include cla Shape { public: Shape(){} ~Shape(){} virtual float GetArea(){ return-1;} }; cla Circle : public Shape { public: Circle(float radius):itsRadius(radius){} ~Circle(){} float GetArea(){ return 3.14 * itsRadius * itsRadius;} private: float itsRadius;}; cla Rectangle : public Shape { public: Rectangle(float len,float width): itsLength(len),itsWidth(width){};~Rectangle(){}; virtual float GetArea(){ return itsLength * itsWidth;} virtual float GetLength(){ return itsLength;} virtual float GetWidth(){ return itsWidth;} private: float itsWidth; float itsLength;}; cla Square : public Rectangle { public: Square(float len);~Square(){} }; Square::Square(float len): Rectangle(len,len){ } void main(){ Shape * sp; sp = new Circle(5);cout GetArea()GetArea()GetArea() 程序运行输出: The area of the Circle is 78.5 The area of the Rectangle is 24 The area of the Square is 25 7-6 定义一个哺乳动物Mammal类,再由此派生出狗Dog类,定义一个Dog类的对象,观察基类与派生类的构造函数与析构函数的调用顺序。 解: 源程序: #include enum myColor{ BLACK,WHITE }; cla Mammal { public: // constructors Mammal();~Mammal(); //acceors int GetAge()const { return itsAge;} void SetAge(int age){ itsAge = age;} int GetWeight()const { return itsWeight;} void SetWeight(int weight){ itsWeight = weight;} //Other methods void Speak()const { cout protected: int itsAge;int itsWeight;}; cla Dog : public Mammal { public: Dog();~Dog(); myColor GetColor()const { return itsColor;} void SetColor(myColor color){ itsColor = color;} void WagTail(){ cout private: myColor itsColor;}; Mammal::Mammal(): itsAge(1),itsWeight(5){ cout Mammal::~Mammal(){ cout Dog::Dog(): itsColor(WHITE){ cout Dog::~Dog(){ cout return 0;} 程序运行输出: Mammal constructor...Dog constructor...Mammal sound!Tail wagging...Fido is 1 years old Dog destructor...Mammal destructor...7-7 定义一个基类,构造其派生类,在构造函数中输出提示信息,观察构造函数的执行情况。 解: #include cla BaseCla { public: BaseCla();}; BaseCla::BaseCla(){ cout cla DerivedCla : public BaseCla { public: DerivedCla();}; DerivedCla::DerivedCla(){ cout void main(){ DerivedCla d;} 程序运行输出: 构造基类对象!构造派生类对象! 7-8 定义一个Document类,有name成员变量,从Document派生出Book类,增加PageCount变量。 解: #include #include cla Document { public: Document(){}; Document(char *name);char *Name;// Document name.void PrintNameOf();// Print name.}; Document::Document(char *name){ Name = new char[ strlen(name)+ 1 ];strcpy(Name, name);}; void Document::PrintNameOf(){ cout } cla Book : public Document { public: Book(char *name, long pagecount);void PrintNameOf();private: long PageCount;};Book::Book(char *name, long pagecount):Document(name){ PageCount = pagecount;} void Book::PrintNameOf(){ cout void main(){ Document a(“Document1”);Book b(“Book1”,100);b.PrintNameOf();} 程序运行输出: Name of book: Book1 7-9 定义基类Base,有两个共有成员函数fn1()、fn2(),私有派生出Derived类,如果想在Derived类的对象中使用基类函数fn1(),应怎么办? 解: cla Base { public: int fn1()const { return 1;} int fn2()const { return 2;} }; cla Derived : private Base { public: int fn1(){ return Base::fn1();};int fn2(){ return Base::fn2();};}; void main(){ Derived a;a.fn1();} 7-10 定义object类,有weight属性及相应的操作函数,由此派生出box类,增加Height和width属性及相应的操作函数,声明一个box对象,观察构造函数与析构函数的调用顺序。 解: #include cla object { private: int Weight;public: object(){ cout int GetWeight(){ return Weight;} void SetWeight(int n){ Weight = n;} ~object(){ cout cla box : public object { private: int Height,Width;public: box(){ cout int GetHeight(){ return Height;} void SetHeight(int n){ Height = n;} int GetWidth(){ return Width;} void SetWidth(int n){ Width = n;} ~box(){ cout void main(){ box a;} 程序运行输出: 构造object对象 构造box对象 析构box对象 析构object对象 7-11 定义一个基类BaseCla,从它派生出类DerivedCla,BaseCla有成员函数fn1()、fn2(),DerivedCla也有成员函数fn1()、fn2(),在主程序中定义一个DerivedCla的对象,分别用DerivedCla的对象以及BaseCla和DerivedCla的指针来调用fn1()、fn2(),观察运行结果。 解: #include cla BaseCla { public: void fn1();void fn2();};void BaseCla::fn1(){ cout cla DerivedCla : public BaseCla { public: void fn1();void fn2();}; void DerivedCla::fn1(){ cout void DerivedCla::fn2(){ cout void main(){ DerivedCla aDerivedCla; DerivedCla *pDerivedCla = &aDerivedCla;BaseCla *pBaseCla = &aDerivedCla; aDerivedCla.fn1();aDerivedCla.fn2();pBaseCla->fn1();pBaseCla->fn2();pDerivedCla->fn1();pDerivedCla->fn2();} 程序运行输出: 调用派生类的函数fn1()调用派生类的函数fn2()调用基类的函数fn1()调用基类的函数fn2()调用派生类的函数fn1()调用派生类的函数fn2() 7-12 为例9-1的吹泡泡程序加一版权(About)对话框。然后修改例9-1的程序,加入以下内容: 程 序: 1.在程序首部加上文件包含命令 #include “resource.h” 2.在框架窗口类之前加入从CDialog类派生的对话框类:// 对话框类 cla CAboutDlg: public CDialog { public: CAboutDlg(); enum {IDD = IDD_DIALOG1};};inline CAboutDlg::CAboutDlg():CDialog(CAboutDlg::IDD){} 3.在框架窗口类中添加响应鼠标右键消息的代码,包括消息响应函数说明、消息响应宏和消息响应函数定义。鼠标右键消息响应函数为: void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point){ CAboutDlg dlg;dlg.DoModal();} 7-13 签名留念簿程序。该程序模仿签名簿,用户使用鼠标左键点击窗口客户区后会弹出一个对话框,输入姓名后可在鼠标点击位置显示出该签名。签名的颜色、字体大小和方向随机确定。说 明:项目建立及添加对话框模板资源的方法同例14-1。修改对话框模板的ID为IDD_NAMEDLG,Caption为“签名对话框”,并添加一个静态文本控件(Caption改为“签名”)和一个编辑控件(ID改为IDC_EDITNAME)。 程 序: // Example 14-2:签名留念簿程序 #include #include “resource.h” // 对话框类 cla CNameDlg: public CDialog { public: CPoint m_pointTopLeft;CString m_strNameEdit;public: CNameDlg();enum {IDD = IDD_NAMEDLG};protected: virtual void DoDataExchange(CDataExchange* pDX);virtual BOOL OnInitDialog();};// 对话框类的构造函数 CNameDlg::CNameDlg():CDialog(CNameDlg::IDD){ m_strNameEdit = _T(“”);} // 数据交换和数据检验 void CNameDlg::DoDataExchange(CDataExchange* pDX){ CDialog::DoDataExchange(pDX);DDX_Text(pDX, IDC_EDITNAME, m_strNameEdit);DDV_MaxChars(pDX, m_strNameEdit, 20);} // 初始化对话框 BOOL CNameDlg::OnInitDialog(){ CDialog::OnInitDialog();CRect rect; GetWindowRect(&rect); rect = CRect(m_pointTopLeft, rect.Size());MoveWindow(rect);return TRUE;} // 签名类 cla CSignal: public CObject { CString m_sName;// 姓名 CPoint m_pointSignal;// 签名位置 int m_nHeight;// 字体高 int m_nColor;// 签名颜色 int m_nEscapement;// 签名倾角 public: CSignal(){} void SetValue(CString name,CPoint point,int height,int color,int escapement); void ShowSignal(CDC *pDC);}; // 签名类成员函数 void CSignal::SetValue(CString name,CPoint point,int height,int color, int escapement){ m_sName = name;m_pointSignal = point;m_nHeight = height;m_nColor = color; m_nEscapement = escapement;} // 显示签名 void CSignal::ShowSignal(CDC *pDC){ CFont *pOldFont, font; font.CreateFont(m_nHeight, 0, m_nEscapement,0, 400, FALSE,FALSE,0, OEM_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, DEFAULT_PITCH, “楷体”); pOldFont = pDC->SelectObject(&font);switch(m_nColor){ case 0: pDC->SetTextColor(RGB(0, 0, 0));break;case 1: pDC->SetTextColor(RGB(255, 0, 0));break;case 2: pDC->SetTextColor(RGB(0, 255, 0));break;case 3: pDC->SetTextColor(RGB(0, 0, 255));break;} pDC->TextOut(m_pointSignal.x, m_pointSignal.y, m_sName);pDC->SelectObject(pOldFont);} // 框架窗口类 #define MAX_NAME 250 cla CMyWnd: public CFrameWnd { CSignal m_signalList[MAX_NAME];int m_nCount;public: CMyWnd(): m_nCount(0){} protected: afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg void OnPaint();DECLARE_MESSAGE_MAP()};// 消息映射 BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)ON_WM_LBUTTONDOWN()ON_WM_PAINT()END_MESSAGE_MAP()// 框架窗口类的成员函数 // 鼠标右键消息响应函数 void CMyWnd::OnLButtonDown(UINT nFlags, CPoint point){ if(m_nCount CString name = dlg.m_strNameEdit; m_signalList[m_nCount].SetValue(name,point,height, color,escapement);m_nCount++;Invalidate();} } } // 绘制框架窗口客户区函数 void CMyWnd::OnPaint(){ CPaintDC dc(this); for(int i=0;i // 应用程序类 cla CMyApp: public CWinApp { public: BOOL InitInstance();}; // 应用程序类的成员函数 BOOL CMyApp::InitInstance(){ CMyWnd *pFrame = new CMyWnd; pFrame->Create(0,_T(“签字留念簿程序”));pFrame->ShowWindow(m_nCmdShow);this->m_pMainWnd = pFrame;return TRUE;} // 全局应用程序对象 CMyApp ThisApp; 7-14 将例14-2的签名留念簿中的对话框改为无模式对话框。用户可用鼠标右键调出签名对话框,并在不退出该对话框的情况下用鼠标左键将输入的签名显示在窗口客户区。 说 明:在向项目中添加对话框模板资源时,要在其属性对话框的More Styles页中选择Visible项。其他同例14-2。 程 序: 该程序中的签名类CSignal和应用程序类与上例相同,因此下面仅列出了框架窗口类和对话框类。由于这两个类的成员函数中存在相互引用的情况,所以我们将框架窗口类的声明放在前面,接下来是对话框类的定义,并在框架窗口类之前加入了一 条对对话框类的声明。最后是这两个类的成员函数定义。// 框架窗口类 #define MAX_NAME 250 cla CNameDlg;cla CMyWnd: public CFrameWnd { CSignal m_signalList[MAX_NAME];int m_nCount;CNameDlg *m_pNameDlg;public: CMyWnd();~CMyWnd();protected: afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg void OnRButtonDown(UINT nFlags, CPoint point);afx_msg void OnPaint();DECLARE_MESSAGE_MAP()};// 对话框类 cla CNameDlg: public CDialog { public: BOOL m_bActive;CString m_strNameEdit;enum {IDD = IDD_NAMEDLG};CNameDlg();BOOL Create();protected: virtual void DoDataExchange(CDataExchange* pDX);virtual BOOL OnInitDialog();virtual void OnOK();virtual void OnCancel();};// 框架窗口类的消息映射 BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)ON_WM_LBUTTONDOWN()ON_WM_RBUTTONDOWN()ON_WM_PAINT()END_MESSAGE_MAP()// 框架窗口类的成员函数 // 框架窗口类的构造函数 CMyWnd::CMyWnd(){ m_nCount = 0;m_pNameDlg = new CNameDlg;} // 框架窗口类的析构函数 CMyWnd::~CMyWnd() { delete m_pNameDlg;} // 鼠标右键消息响应函数 void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point){ if(m_pNameDlg->m_bActive) m_pNameDlg->SetActiveWindow();// 激活对话框 else m_pNameDlg->Create();// 显示对话框 } // 鼠标左键消息响应函数 void CMyWnd::OnLButtonDown(UINT nFlags, CPoint point){ if(m_nCount int height = rand()%60+12;int color = rand()%4; int escapement =(rand()%1200)-600;CString name = m_pNameDlg->m_strNameEdit; m_signalList[m_nCount].SetValue(name, point, height, color, escapement);m_nCount++;Invalidate();} } // 绘制框架窗口客户区函数 void CMyWnd::OnPaint(){ CPaintDC dc(this); for(int i=0;i // 对话框类的成员函数 // 对话框类的构造函数 CNameDlg::CNameDlg():CDialog(CNameDlg::IDD){ m_bActive = FALSE;m_strNameEdit = _T(“”);} // 数据交换 void CNameDlg::DoDataExchange(CDataExchange* pDX){ CDialog::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT1, m_strNameEdit);} // 初始化对话框 BOOL CNameDlg::OnInitDialog(){ CDialog::OnInitDialog();CRect rect;GetWindowRect(&rect);MoveWindow(0, 0, rect.Width(), rect.Height());return TRUE;} // 显示无模态对话框 BOOL CNameDlg::Create(){ m_bActive = TRUE;return CDialog::Create(CNameDlg::IDD);} // 退出对话框 void CNameDlg::OnCancel(){ m_bActive = FALSE;DestroyWindow();} // 更新数据 void CNameDlg::OnOK(){ UpdateData(TRUE);} 7-15 为例14-2的签名程序加上字体选择对话框。 说 明:本程序使用字体选择公用对话框(通过鼠标右键调出)选择签名的字体、字号和颜色等参数,在签名对话框中要输入姓名和签名与X轴的倾斜角。建立项目的方法与例14-2相似,只是要在签名对话框模板中再添加一个编辑控件用于输入签名的倾斜角,其标识符为IDD_EDIT2。 程 序: // Example 14-4:签名留念簿程序 #include #include #include #include “resource.h” // 对话框类 cla CNameDlg: public CDialog { public: CPoint m_pointTopLeft;// 对话框位置 CString m_strNameEdit;// 签名 LONG m_lEscapement;// 签名倾角 public: CNameDlg(); enum {IDD = IDD_NAMEDLG};protected: virtual void DoDataExchange(CDataExchange* pDX);virtual BOOL OnInitDialog();}; // 对话框类的构造函数 CNameDlg::CNameDlg():CDialog(CNameDlg::IDD), m_pointTopLeft(0, 0){ m_strNameEdit = _T(“”);m_lEscapement = 0;} // 数据交换和数据检验 void CNameDlg::DoDataExchange(CDataExchange* pDX){ CDialog::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT1, m_strNameEdit);DDX_Text(pDX, IDC_EDIT2, m_lEscapement);DDV_MaxChars(pDX, m_strNameEdit, 20); DDV_MinMaxLong(pDX, m_lEscapement,-600, 600);} // 初始化对话框 BOOL CNameDlg::OnInitDialog(){ CDialog::OnInitDialog();CRect rect; GetWindowRect(&rect); rect = CRect(m_pointTopLeft, rect.Size());MoveWindow(rect);return TRUE;} // 签名类 cla CSignal: public CObject { CString m_strSignal;// 姓名 COLORREF m_colorSignal;// 签名颜色 CPoint m_pointSignal;// 签名位置 LOGFONT m_fontSignal;// 签名字体 public: CSignal(){} void SetValue(CString signal, CPoint point, COLORREF color,LONG escapement, LOGFONT *pfont);void ShowSignal(CDC *pDC);}; // 签名类成员函数 void CSignal::SetValue(CString signal, CPoint point, COLORREF color, int escapement, LOGFONT *pfont){ m_strSignal = signal;m_pointSignal = point;m_colorSignal = color;memcpy(&m_fontSignal, pfont, sizeof(LOGFONT));m_fontSignal.lfEscapement = escapement;} // 显示签名 void CSignal::ShowSignal(CDC *pDC){ CFont font, *pOldFont;font.CreateFontIndirect(&m_fontSignal);pOldFont = pDC->SelectObject(&font);pDC->SetTextColor(m_colorSignal);pDC->TextOut(m_pointSignal.x, m_pointSignal.y, m_strSignal);pDC->SelectObject(pOldFont);} // 框架窗口类 #define MAX_NAME 250 cla CMyWnd: public CFrameWnd { CSignal m_signalList[MAX_NAME];// 签名数组 int m_nCount;// 签名数量 LOGFONT m_fontSignal;// 签名字体 COLORREF m_colorSignal;// 签名颜色 public: CMyWnd();protected: afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg void OnRButtonDown(UINT nFlags, CPoint point);afx_msg void OnPaint();DECLARE_MESSAGE_MAP()};// 消息映射 BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)ON_WM_LBUTTONDOWN()ON_WM_RBUTTONDOWN()ON_WM_PAINT()END_MESSAGE_MAP()// 框架窗口类的成员函数 CMyWnd::CMyWnd(){ m_nCount = 0; m_colorSignal = RGB(0, 0, 0);m_fontSignal.lfHeight = 40;m_fontSignal.lfWidth = 0;m_fontSignal.lfEscapement = 0;m_fontSignal.lfOrientation = 0;m_fontSignal.lfWeight = 400;m_fontSignal.lfItalic = FALSE;m_fontSignal.lfUnderline = FALSE;m_fontSignal.lfStrikeOut = 0; m_fontSignal.lfCharSet = OEM_CHARSET; m_fontSignal.lfOutPrecision = OUT_DEFAULT_PRECIS;m_fontSignal.lfClipPrecision = CLIP_DEFAULT_PRECIS;m_fontSignal.lfQuality = DEFAULT_QUALITY;m_fontSignal.lfPitchAndFamily = DEFAULT_PITCH;strcpy(m_fontSignal.lfFaceName, “Arial”);} // 鼠标右键消息响应函数 void CMyWnd::OnLButtonDown(UINT nFlags, CPoint point){ if(m_nCount CNameDlg dlg; dlg.m_pointTopLeft = point;if(dlg.DoModal()== IDOK){ LONG escapement = dlg.m_lEscapement;CString name = dlg.m_strNameEdit;m_signalList[m_nCount].SetValue(name, point,m_colorSignal,escapement, &m_fontSignal);m_nCount++;Invalidate();} } } // 鼠标右键消息响应函数 void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point){ CFontDialog dlg(&m_fontSignal);if(dlg.DoModal()== IDOK){ dlg.GetCurrentFont(&m_fontSignal);m_colorSignal = dlg.GetColor();} } // 绘制框架窗口客户区函数 void CMyWnd::OnPaint(){ CPaintDC dc(this);for(int i=0;i cla CMyApp: public CWinApp { public: BOOL InitInstance();};// 应用程序类的成员函数 BOOL CMyApp::InitInstance(){ CMyWnd *pFrame = new CMyWnd;pFrame->Create(0,_T(“签字留念簿程序”));pFrame->ShowWindow(SW_SHOWMAXIMIZED);this->m_pMainWnd = pFrame;return TRUE;} // 全局应用程序对象 CMyApp ThisApp; 7-16 为例9-3的吹泡泡程序添加颜色选择对话框,使其可以绘出五颜六色的泡泡。 程 序:在例9-3的程序基础上作如下修改: 1.在程序首部添加文件包含命令: #include 2.在框架窗口类声明中添加一个COLORREF类型的数组,存放各泡泡的颜色: COLORREF m_colorBubble [MAX_BUBBLE];3.修改鼠标左键消息映射函数,添加使用颜色选择公用对话框的代码: void CMyWnd::OnLButtonDown(UINT nFlags, CPoint point){ if(m_nBubbleCount InvalidateRect(rect, FALSE);} } 4.修改OnPaint()成员函数,添加根据泡泡颜色使用画刷的代码: void CMyWnd::OnPaint(){ CPaintDC dc(this); CBrush brushNew, *pbrushOld;for(int i=0;i brushNew.CreateSolidBrush(m_colorBubble[i]);pbrushOld = dc.SelectObject(&brushNew);dc.Ellipse(m_rectBubble[i]);dc.SelectObject(pbrushOld);brushNew.DeleteObject();} } 7-17 序列化。如果例12-1的吹泡泡程序使用一般的数组存放泡泡数据(参看例9-1的程序): CRect m_rectBubble[MAX_BUBBLE];int m_nBubbleCount; 为其文档类重新设计Serialize()函数。 说 明:按例12-1的方法建立项目和输入源代码,但将文档类中的泡泡数据改为以上两行的形式。修改文档类的Serialize()函数,代码如下。 程 序: // 序列化函数 void CMyDoc::Serialze(CArchive& ar){ if(ar.IsStoring()){ ar for(int i=0;i ar >> m_nBubbleCount; for(int i=0;i> m_rectBubble[i];} } 7-18 修改例12-1的程序并观察其打印结果。 程 序: 在例12-1程序的视图类CMyView类的成员函数OnDraw()中,添加代码沿窗口客户区轮廓画一矩形: void CMyView::OnDraw(CDC* pDC){ CRect rect;GetClientRect(&rect);pDC->Rectangle(rect); CMyDoc* pDoc = GetDocument();// 取文档指针 ASSERT_VALID(pDoc);pDC->SelectStockObject(LTGRAY_BRUSH);// 在视图上显示文档数据 for(int i=0;i GetListSize();i++)pDC->Ellipse(pDoc->GetBubble(i));} 7-19 改进吹泡泡程序,使之打印输出与屏幕显示的比例相近。 程 序: 在例12-1基础上修改。首先在CMyView类中重载虚函数OnPrepareDC()。在CMyView类的声明中增加一行: virtual void OnPrepareDC(CDC *pDC,CPrintInfo *pInfo=NULL);然后添加该函数的定义,设置映射模式为MM_LOMETRIC: // 设置映射模式 void CMyView::OnPrepareDC(CDC *pDC, CPrintInfo *pInfo){ pDC->SetMapMode(MM_LOMETRIC);CView::OnPrepareDC(pDC, pInfo);} 然后修改消息映射函数OnLButtonDown(),将物理坐标转换为逻辑坐标: // 响应点击鼠标左键消息 void CMyView::OnLButtonDown(UINT nFlags, CPoint point){ CMyDoc* pDoc = GetDocument();// 取文档指针 ASSERT_VALID(pDoc);CClientDC dc(this);// 设置设备环境 OnPrepareDC(&dc); int r = rand()%50+5;// 生成泡泡 CRect rect(point.x-r, point.y-r, point.x+r, point.y+r);InvalidateRect(rect, FALSE);// 更新视图 dc.DPtoLP(rect);// 转换物理坐标为逻辑坐标 pDoc->AddBubble(rect);// 修改文档数据 pDoc->SetModifiedFlag();// 设置修改标志 } 7-20 声明一个Person类,并使之支持序列化。 程 序: cla CPerson: public CObject { DECLARE_SERIAL(CPerson)LONG m_IDnumber;// 身份证号码 CString m_strName;// 姓名 CString m_strNation;// 民族 int m_nSex;// 性别 int m_nAge;// 年龄 BOOL m_bMarried;// 婚否 public: CEmployee(){}; CPerson& operator =(CPerson& person);void Serialize(CArchive& ar);}; IMPLEMENT_SERIAL(CPerson, CObject, 1)CPerson& CPerson::operator =(CPerson& person){ m_IDnumber = person.m_IDnumber;m_strName = person.m_strName;m_strNation = person.m_strNation;m_nSex = person.m_nSex;m_nAge = person.m_nAge; m_bMarried = person.m_bMarried;return *this;} void CPerson::Serialize(CArchive& ar){ CObject::Serialize(ar);// 首先调用基类的Serialize()方法 if(ar.IsStoring()){ ar ar > m_IDnumber;ar >> m_strName;ar >> m_strNation;ar >> m_nSex;CFont *pOldFont =(CFont *)(pDC->SelectObject(&font));CRect rectPaper = pInfo->m_rectDraw;// 取页面打印矩形 // 页眉: 页面顶端中央打印文档名称 CMyDoc *pDoc = GetDocument();ASSERT_VALID(pDoc);CString str;str.Format(“Bubble (LPCSTR)pDoc->GetTitle()); CSize sizeText = pDC->GetTextExtent(str); CPoint point((rectPaper.Width()-sizeText.cx)/2, 0);Report: %s”, ar >> m_nAge;ar >>(int)m_bMarried;} } 7-21 修改例13-3的吹泡泡程序,使其打印每个泡泡的数据值。打印格式为每页40行,页眉为文档名,页脚为页号。说 明:首先为视图类添加一个数据成员m_nLinePerPage,用来存放每页行数,并在视图类CMyView的构造函数中将m_nLinePerPage初始化为40。 修改视图类成员函数OnPrepareDC(),设置映射模式为MM_TWIPS。该模式为每英寸1440点,很适合打印机输出。 程 序: 重载视图类的成员函数OnPreparePrinting(),在其中添加计算打印页数的代码: BOOL CMyView::OnPreparePrinting(CPrintInfo* pInfo){ CMyDoc *pDoc = GetDocument();int nPageCount = pDoc->GetListSize()/m_nLinePerPage;if(pDoc->GetListSize()% m_nLinePerPage)nPageCount ++;pInfo->SetMaxPage(nPageCount);return DoPreparePrinting(pInfo);} 最后重载视图类的OnPrint()函数并添加打印代码: void CMyView::OnPrint(CDC* pDC, CPrintInfo* pInfo){ int nPage = pInfo->m_nCurPage;// 当前页号 int nStart =(nPage-1)*m_nLinePerPage;// 本页第一行 int nEnd = nStart+m_nLinePerPage;// 本页最后一行 CFont font;// 设置字体 font.CreateFont(-280, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_MODERN, “Courier New”); pDC->TextOut(point.x, point.y, str);point.x = rectPaper.left;// 打印页眉下划线 point.y = rectPaper.top-sizeText.cy;pDC->MoveTo(point);point.x = rectPaper.right;pDC->LineTo(point);// 打印表头 str.Format(“%6.6s %6.6s %6.6s %6.6s %6.6s”, “Index”, “Left”, “Top”, “Right”, “Bottom”);point.x = 720;point.y-= 720; pDC->TextOut(point.x, point.y, str);TEXTMETRIC tm;// 取当前字体有关信息 pDC->GetTextMetrics(&tm); int nHeight = tm.tmHeight+tm.tmExternalLeading;point.y-= 360;// 下移 1/4 英寸 for(int i=nStart;i if(i >= pDoc->GetListSize())break; str.Format(“%6d %6d %6d %6d %6d”, i+1, pDoc->GetBubble(i).left, pDoc->GetBubble(i).top, pDoc->GetBubble(i).right, pDoc->GetBubble(i).bottom);point.y-= nHeight; pDC->TextOut(point.x, point.y, str);} // 在页面底部中央打印页号 str.Format(“-%d-”, nPage);sizeText = pDC->GetTextExtent(str); point.x =(rectPaper.Width()-sizeText.cx)/2;point.y = rectPaper.Height()+sizeText.cy;pDC->TextOut(point.x, point.y, str);// 释放字体对象 pDC->SelectObject(pOldFont);} 7-22 修改例11-4的拼图程序,使之在难度菜单的相应选项前打钩。 程 序: 首先在框架窗口类的消息响应函数声明处增加以下消息响应函数的声明: afx_msg void CPuzzleWnd::OnUpdateGrad01(CCmdUI* pCmdUI);afx_msg void CPuzzleWnd::OnUpdateGrad02(CCmdUI* pCmdUI);afx_msg void CPuzzleWnd::OnUpdateGrad03(CCmdUI* pCmdUI);然后在框架窗口类的消息映射宏中加入相应内容: BEGIN_MESSAGE_MAP(CPuzzleWnd, CFrameWnd)ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_MOUSEMOVE()ON_WM_PAINT()ON_COMMAND(ID_SHOWFIG, OnShowFig)ON_COMMAND(ID_GRAD01, OnGrad01)ON_COMMAND(ID_GRAD02, OnGrad02)ON_COMMAND(ID_GRAD03, OnGrad03)ON_UPDATE_COMMAND_UI(ID_GRAD01, OnUpdateGrad01)ON_UPDATE_COMMAND_UI(ID_GRAD02, OnUpdateGrad02)ON_UPDATE_COMMAND_UI(ID_GRAD03, OnUpdateGrad03)END_MESSAGE_MAP()注意更新命令用户接口消息映射宏将菜单标识符与相应的消息映射函数联系在一起。最后编写相应的更新命令用户接口消息映射函数: void CPuzzleWnd::OnUpdateGrad01(CCmdUI* pCmdUI){ pCmdUI->SetCheck(m_nColCount == 4);} void CPuzzleWnd::OnUpdateGrad02(CCmdUI* pCmdUI){ pCmdUI->SetCheck(m_nColCount == 8);} void CPuzzleWnd::OnUpdateGrad03(CCmdUI* pCmdUI){ pCmdUI->SetCheck(m_nColCount == 16);} 输入输出:在选择拼图难度时,可在相应选项前打钩(图13-4)。 // Example 13-7: 七巧板程序 ////////////////////////////////// #include #include // 拼 板 类 //////////////////////////////////////////////////// #define MAX_POINTS 4 #define CHIP_WIDTH 240 #define DELTA 30 cla CChip : public CObject { DECLARE_SERIAL(CChip)int m_nType; CPoint m_pointList[MAX_POINTS];int m_nPointCount;public: CChip(){} void SetChip(int type, POINT *ppointlist, int count);void DrawChip(CDC *pDC);BOOL PtInChip(POINT point);LPCRECT GetRect(); void MoveTo(CSize offset);void Rotation(); void Serialize(CArchive &ar);}; IMPLEMENT_SERIAL(CChip, CObject, 1)// 设置拼图块参数 void CChip::SetChip(int type, POINT *ppointlist, int count){ m_nType = type;m_nPointCount = count;for(int i=0;i // 绘出拼图块 void CChip::DrawChip(CDC *pDC){ CPen penNew, *ppenOld;CBrush brushNew, *pbrushOld;switch(m_nType){ case 1: brushNew.CreateSolidBrush(RGB(127, 127, 127));break;case 2: brushNew.CreateSolidBrush(RGB(255, 0, 0));break; case 3: brushNew.CreateSolidBrush(RGB(0, 255, 0));break;case 4: brushNew.CreateSolidBrush(RGB(0, 0, 255));break;case 5: brushNew.CreateSolidBrush(RGB(127, 127, 0));break;case 6: brushNew.CreateSolidBrush(RGB(127, 0, 127));break;case 7: brushNew.CreateSolidBrush(RGB(0, 127, 127));break;} penNew.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));ppenOld = pDC->SelectObject(&penNew);pbrushOld = pDC->SelectObject(&brushNew);pDC->Polygon(m_pointList, m_nPointCount);pDC->SelectObject(ppenOld);pDC->SelectObject(pbrushOld);} // 检测一点是否在拼图块中 BOOL CChip::PtInChip(POINT point){ CRgn rgn;rgn.CreatePolygonRgn(m_pointList, m_nPointCount, 0);return rgn.PtInRegion(point);} // 取拼图块的包含矩形 LPCRECT CChip::GetRect(){ static RECT rect;CRgn rgn;rgn.CreatePolygonRgn(m_pointList, m_nPointCount, 0);rgn.GetRgnBox(&rect);rect.right++;rect.bottom++;return ▭} // 旋转拼图块 void CChip::Rotation(){ CRect rect;CRgn rgn;rgn.CreatePolygonRgn(m_pointList, m_nPointCount, 0);rgn.GetRgnBox(&rect); double x = rect.left+rect.Width()/2;// 计算旋转中心 double y = rect.top+rect.Height()/2;double dx, dy; for(int i=0;i dx = m_pointList[i].x-x;dy = m_pointList[i].y-y; m_pointList[i].x =(int)(x+dx*0.7071-dy*0.7071);m_pointList[i].y =(int)(y+dx*0.7071+dy*0.7071);} } // 移动拼图块 void CChip::MoveTo(CSize offset){ for(int i=0;i // 序列化 void CChip::Serialize(CArchive &ar){ if(ar.IsStoring()){ ar for(int i=0;i ar >> m_nType;ar >> m_nPointCount; for(int i=0;i> m_pointList[i];} } // 文 档 类 //////////////////////////////////////////////////// #define CHIP_COUNT 7 cla CMyDoc : public CDocument { DECLARE_DYNCREATE(CMyDoc)CChip m_chipList[CHIP_COUNT];public: void Reset(); virtual void DeleteContents();virtual void Serialize(CArchive& ar);}; IMPLEMENT_DYNCREATE(CMyDoc, CDocument) // 初始化拼图块 void CMyDoc::Reset(){ POINT pointList[MAX_POINTS];pointList[0].x = DELTA;pointList[0].y = DELTA;pointList[1].x = DELTA+CHIP_WIDTH;pointList[1].y = DELTA;pointList[2].x = DELTA+CHIP_WIDTH/2;pointList[2].y = DELTA+CHIP_WIDTH/2;m_chipList[0].SetChip(1, pointList, 3); pointList[0].x = DELTA;pointList[0].y = DELTA;pointList[1].x = DELTA;pointList[1].y = DELTA+CHIP_WIDTH;pointList[2].x = DELTA+CHIP_WIDTH/2;pointList[2].y = DELTA+CHIP_WIDTH/2;m_chipList[1].SetChip(2, pointList, 3); pointList[0].x = DELTA+CHIP_WIDTH;pointList[0].y = DELTA;pointList[1].x = DELTA+CHIP_WIDTH;pointList[1].y = DELTA+CHIP_WIDTH/2;pointList[2].x = DELTA+(CHIP_WIDTH*3)/4;pointList[2].y = DELTA+CHIP_WIDTH/4;m_chipList[2].SetChip(3, pointList, 3); pointList[0].x = DELTA+CHIP_WIDTH/2;pointList[0].y = DELTA+CHIP_WIDTH/2;pointList[1].x = DELTA+CHIP_WIDTH/4;pointList[1].y = DELTA+(CHIP_WIDTH*3)/4;pointList[2].x = DELTA+(CHIP_WIDTH*3)/4;pointList[2].y = DELTA+(CHIP_WIDTH*3)/4;m_chipList[3].SetChip(4, pointList, 3); pointList[0].x = DELTA+CHIP_WIDTH;pointList[0].y = DELTA+CHIP_WIDTH/2;pointList[1].x = DELTA+CHIP_WIDTH;pointList[1].y = DELTA+CHIP_WIDTH;pointList[2].x = DELTA+CHIP_WIDTH/2;pointList[2].y = DELTA+CHIP_WIDTH;m_chipList[4].SetChip(5, pointList, 3); pointList[0].x = DELTA+(CHIP_WIDTH*3)/4;pointList[0].y = DELTA+CHIP_WIDTH/4;pointList[1].x = DELTA+CHIP_WIDTH/2;pointList[1].y = DELTA+CHIP_WIDTH/2; pointList[2].x = DELTA+(CHIP_WIDTH*3)/4;pointList[2].y = DELTA+(CHIP_WIDTH*3)/4;pointList[3].x = DELTA+CHIP_WIDTH;pointList[3].y = DELTA+CHIP_WIDTH/2;m_chipList[5].SetChip(6, pointList, 4); pointList[0].x = DELTA; pointList[0].y = DELTA+CHIP_WIDTH;pointList[1].x = DELTA+CHIP_WIDTH/4;pointList[1].y = DELTA+(CHIP_WIDTH*3)/4;pointList[2].x = DELTA+(CHIP_WIDTH*3)/4;pointList[2].y = DELTA+(CHIP_WIDTH*3)/4; pointLis ¨t[3].x = DELTA+CHIP_WIDTH/2;pointList[3].y = DELTA+CHIP_WIDTH;m_chipList[6].SetChip(7, pointList, 4);// 清理文档:关闭文档、建立新文档和打开文档前调用 void CMyDoc::DeleteContents(){ Reset(); CDocument::DeleteContents();} // 系列化:读写文档时自动调用 void CMyDoc::Serialize(CArchive &ar){ for(int i=0;i 视 图 类 /////////////////////////////////////////////////// cla CMyView : public CView { DECLARE_DYNCREATE(CMyView)BOOL m_bCaptured;CPoint m_pointMouse;int m_nCurrIndex;public: CMyView(){m_bCaptured = FALSE;} CMyDoc* GetDocument(){return(CMyDoc*)m_pDocument;} virtual void OnInitialUpdate(); virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);virtual void OnDraw(CDC* pDC); afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg void OnLButtonUp(UINT nFlags, CPoint point);afx_msg void OnMouseMove(UINT nFlags, CPoint point);afx_msg void OnRButtonDown(UINT nFlags, CPoint point);DECLARE_MESSAGE_MAP()}; IMPLEMENT_DYNCREATE(CMyView, CView) BEGIN_MESSAGE_MAP(CMyView, CView)ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_MOUSEMOVE()ON_WM_RBUTTONDOWN()ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)END_MESSAGE_MAP()// 更新初始化:当建立新文档或打开文档时调用 void CMyView::OnInitialUpdate(){ CView::OnInitialUpdate();Invalidate();} // 绘制视图:程序开始运行或窗体发生变化时自动调用 void CMyView::OnDraw(CDC* pDC){ CMyDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);for(int i=0;im_chipList[i].DrawChip(pDC);} // 消息响应:用户点击鼠标左键时调用 void CMyView::OnLButtonDown(UINT nFlags, CPoint point){ CMyDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);for(int i=CHIP_COUNT-1;i>=0;i--)if(pDoc->m_chipList[i].PtInChip(point)){ SetCapture();m_bCaptured = TRUE;m_pointMouse = point;m_nCurrIndex = i;break;} } // 释放鼠标左键 void CMyView::OnLButtonUp(UINT nFlags, CPoint point){ if(m_bCaptured){ ::ReleaseCapture();m_bCaptured = FALSE;} } // 移动鼠标左键 void CMyView::OnMouseMove(UINT nFlags, CPoint point){ if(m_bCaptured){ CMyDoc* pDoc = GetDocument();ASSERT_VALID(pDoc); InvalidateRect(pDoc->m_chipList[m_nCurrIndex].GetRect()); CSize offset(point-m_pointMouse); pDoc->m_chipList[m_nCurrIndex].MoveTo(offset);InvalidateRect(pDoc->m_chipList[m_nCurrIndex].GetRect()); m_pointMouse = point;pDoc->SetModifiedFlag();} } // 按下鼠标右键: 旋转拼图块 void CMyView::OnRButtonDown(UINT nFlags, CPoint point){ CMyDoc* pDoc = GetDocument();ASSERT_VALID(pDoc); for(int i=CHIP_COUNT-1;i>=0;i--)if(pDoc->m_chipList[i].PtInChip(point)){ InvalidateRect(pDoc->m_chipList[i].GetRect());pDoc->m_chipList[i].Rotation(); InvalidateRect(pDoc->m_chipList[i].GetRect(), FALSE);pDoc->SetModifiedFlag();break;} } // 准备打印:设置打印参数 BOOL CMyView::OnPreparePrinting(CPrintInfo* pInfo){ pInfo->SetMaxPage(1); return DoPreparePrinting(pInfo);} // 主 框 架 类 ////////////////////////////////////////////////// cla CMainFrame : public CFrameWnd { DECLARE_DYNCREATE(CMainFrame)}; IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)// 应 用 程 序 类 /////////////////////////////////////////////// #define IDR_MAINFRAME 128 // 主框架的资源代号 cla CMyApp : public CWinApp { public: virtual BOOL InitInstance();DECLARE_MESSAGE_MAP()};BEGIN_MESSAGE_MAP(CMyApp, CWinApp)ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)END_MESSAGE_MAP()// 初始化程序实例:建立并登记文档模板 BOOL CMyApp::InitInstance(){ CSingleDocTemplate* pDocTemplate;pDocTemplate = new CSingleDocTemplate(IDR_MAINFRAME, RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CMyView));AddDocTemplate(pDocTemplate);CCommandLineInfo cmdInfo;ParseCommandLine(cmdInfo);if(!ProceShellCommand(cmdInfo))return FALSE;m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);return TRUE;} // 全局应用程序对象 CMyApp theApp; 7-23 为例9-3的吹泡泡程序添加一标识符为IDI_MAINICON的图标(该图标应已按11.8:“向项目中添加资源”中的方法建立并加入项目)。 说 明:建立项目的方法见9.8:“用Visual C++集成开发环境开发Win32应用程序”。 程 序: 在例9-3程序前面添加一文件包含命令: #include ”resource.h” 并将CMyApp::InitInstance()函数修改为: BOOL CMyApp::InitInstance(){ HICON hIcon; hIcon = LoadIcon(IDI_MAINICON);// 载入图标 CMyWnd *pFrame = new CMyWnd;pFrame->Create(0,_T(“吹泡泡程序”)); pFrame->SetIcon(hIcon, TRUE);// 设置大图标 pFrame->SetIcon(hIcon, FALSE);// 设置小图标 pFrame->ShowWindow(m_nCmdShow);this->m_pMainWnd = pFrame;return TRUE;} 7-24 显示一张位图文件(.BMP)。 说 明:首先建立Win32 Application空白项目和源代码文件(不要忘记设置项目使之可以使用MFC类库),然后按11.8:“向项目中添加资源”的方法为项目建立资源文件,并将待显示的位图文件作为资源装入项目。 程 序: // Example 11-2:显示BMP图片 #include #include “resource.h” // 框架窗口类 cla CMyWnd: public CFrameWnd { CBitmap m_Bitmap;int m_nHeight;int m_nWidth;public: CMyWnd();protected: afx_msg void OnPaint();DECLARE_MESSAGE_MAP()}; // 消息映射 BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)ON_WM_PAINT()END_MESSAGE_MAP()// 框架窗口类的成员函数 CMyWnd::CMyWnd(){ m_Bitmap.LoadBitmap(IDB_BITMAP1);BITMAP BM; m_Bitmap.GetBitmap(&BM);m_nWidth = BM.bmWidth;m_nHeight = BM.bmHeight;} // 响应绘制窗口客户区消息 void CMyWnd::OnPaint(){ CPaintDC dc(this);CDC MemDC;MemDC.CreateCompatibleDC(NULL);MemDC.SelectObject(&m_Bitmap);dc.BitBlt(0,0,m_nWidth,m_nHeight,&MemDC,0,0,SRCCOPY);} // 应用程序类 cla CMinMFCApp: public CWinApp { public: BOOL InitInstance();};// 应用程序类的成员函数 // 初始化应用程序实例 BOOL CMinMFCApp::InitInstance(){ CMyWnd *pFrame = new CMyWnd;pFrame->Create(0,_T(“Beautiful Cats”));pFrame->ShowWindow(m_nCmdShow);this->m_pMainWnd = pFrame;return TRUE;} // 全局应用程序对象 CMinMFCApp ThisApp; 7-25 修改11-2,使之可以不同比例放大或缩小图象。说 明:使用StretchBlt()函数代替BitBlt()函数就可实现图象的缩放显示。在项目中加入一个弹出式菜单(将标识符改为IDR_MAINMENU),内含3个菜单选项:缩小1倍显示,按原尺寸显示和放大1倍显示,其标识符分别改为ID_SHRINK,ID_BESTFIT和ID_ZOOMOUT。 程 序: // Example 11-3:以不同尺寸显示BMP图片 #include #include ”resource.h" // 框架窗口类 cla CMyWnd: public CFrameWnd { CBitmap m_Bitmap;float m_fTimes;int m_nHeight; int m_nWidth;public: CMyWnd(); BOOL PreCreateWindow(CREATESTRUCT &cs);protected: afx_msg void OnPaint();afx_msg void OnShrink();afx_msg void OnBestFit();afx_msg void OnZoomOut();DECLARE_MESSAGE_MAP()}; // 消息映射 BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)ON_WM_PAINT() ON_COMMAND(ID_SHRINK, OnShrink)ON_COMMAND(ID_BESTFIT, OnBestFit)ON_COMMAND(ID_ZOOMOUT, OnZoomOut)END_MESSAGE_MAP()// 主窗口类的成员函数 CMyWnd::CMyWnd(){ BITMAP BM; m_Bitmap.LoadBitmap(IDB_BITMAP1);m_Bitmap.GetBitmap(&BM);m_nWidth = BM.bmWidth;m_nHeight = BM.bmHeight;m_fTimes = 1.0;} // 装入菜单 BOOL CMyWnd::PreCreateWindow(CREATESTRUCT &cs){ cs.hMenu = LoadMenu(NULL,MAKEINTRESOURCE(IDR_MAINMENU));return CFrameWnd::PreCreateWindow(cs);} // 缩小图象 void CMyWnd::OnShrink(){ m_fTimes = 0.5;Invalidate();} // 放大图象 void CMyWnd::OnZoomOut(){ m_fTimes = 2.0;Invalidate();} // 原样显示