Visual C++ 实用教程 第4版 - 郑阿奇 - - 习题参考答案

更新时间:2024-04-16 06:31:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

1.7 指针和引用

55. 已知int d=5, *pd=&d, b=3; 求下列表达式的值。

A. *pd*b B. ++*pd-b C. *pd++ D. ++(*pd)

答:15, 3 , 5, 6

56.选择填充。

(1)选择正确的说明语句为( )。

A. int N['b']; B. int N[4,9]; C. int N[][]; D. int *N[10]; 答:B

(2)若有定义:int a=100,*p=&a;则*p的值是( )。 A.变量p的地址 B. 变量a的地址值 C.变量a的值 D.无意义 答:C.

(3)下述程序的输出结果是( )。 #include void main()

{

int a[5]={2,4,6,8,10};

int *p=a, **q=&p;

cout<<*(p++)<<','<< **q; }

A. 4,4 B. 2,2 C. 4,2 D. 4,5 答:B

(4)下述程序片段的输出是( )。 int a[3][4]={{1,2,3,4},{5,6,7,8}}; int x, *p=a[0];

x=(*p)*(*p+2)*(*p+4); cout<

A. 15 B. 14 C. 16 D. 13 答:A

(5)若有以下定义,则下列对数组引用正确的是( )。 int (*q)[3] = new int[2][3];

A. q[2][3] B. *q C. *(*q+2) D. *(*(q+2)+3) 答:C

(6)若要用如下程序片段使指针变量p指向一个存储动态分配的存储单元: float *p;

p=(float * ) new float;

则空白处应填入:

A.float * B. *float C 省略; D.( float )

(7)下列表示引用的方法中,( )是正确的。 已知:int m=10;

A. int &x=m; B. int &y= 10; C.int &z; D. float &t = &m; 答:A

57.分析下列程序的结果。 #include int &fun( int n, int s[]) { int &m=s[n]; return m; }

void main()

{ int s[] ={15,4,3,2,1,0}; fun(3, s)=10;

cout<

答:10

58.用指针作为函数的参数,设计一个实现两个参数交换的函数。输入3个实数,按升序排序后输出。

59.编写函数void fun(int *a,int *n,int pos,int x);其功能是将x值插入到指针a所指的一维数组中,其中指针n所指存储单元中存放的是数组元素个数,pos为指定插入位置的下标。

60.编写函数void fun(char *s),其功能是将s所指的字符串逆序存放。

61 输入一个字符串, 串内有数字和非数字字符, 例如,\345fdf678jdhfg945\。将其中连续的数字作为一个整数,依次存放到另一个整型数组b中。如将2345存放到b[O]、345放入b[1]、678放入b[2]、??统计出字符串中的整数个数,并输出这些整数。要求在主函数中完成输入和输出工作。设计一个函数,把指向字符串的指针和指向整数的指针作为函数的参数,并完成从字符串中依次提取出整数的工作。

62.有5个学生,每个学生的数据结构包括学号、姓名、年龄、C++成绩、数学成绩和英语成绩、总平均分,从键盘输入5个学生的学号、姓名、3门课的成绩,计算3门课的总平均分,最后将5个学生的数据输出。要求各个功能用函数来实现。

第2章 C++面向对象程序设计

2.1 类和对象

1.什么是类?类的定义格式?类的成员一般分为哪两部分?它们的区别如何? ⑴“类”是对具有共同的属性特征和行为特征的对象的概括和抽象。 ⑵类的定义格式: class 类名{

[ private:]

私有数据成员和成员函数 public:

公有数据成员和成员函数 };

⑶类的成员一般分为数据成员和成员函数两部分。

⑷数据成员一般用来表示对象属性特征,而成员函数一般表示了对象的可以进行的操作,即行为特征。

2.类与结构体有什么区别?

类中可以包含两类成员――数据成员和成员函数;而标准C语言中的结构体只能包含数据成员;但是C++中的结构体对C语言中的结构体有扩展,C++中的结构体也可以两类成员――数据成员和成员函数;因此C++中的类和C++中的结构体出来在定义方式上不一样之外(class,struct ),还有就是它们的缺省封装字是不一样的,一个是private,一个是public。

3.什么是对象?如何定义一个对象?对象的成员如何表示? ⑴对象是类的实例,是类的变量。 ⑵对象的定义: 类名 对象名称; 或:类名 * 对象指针;

⑶对象成员的表示:对象名称.成员名字;

或: 对象指针→成员名字; 4.什么是构造函数?构造函数有哪些特点?

构造函数是类的成员函数,它有以下特点:

? 构造函数的名字必须与类名相同。

? 构造函数可以有任意的形参,但不能具有返回值。 ? 定义对象时,编译系统会自动地调用构造函数。 ? 构造函数可以重载

5.什么是析构函数?析构函数有哪些特点?

析构函数也是类的成员函数,它有以下特点:

? 析构函数名也应与类名相同,只是在函数名前面加一个波浪符~。 ? 析构函数不能带任何参数,也没有返回值。

? 每个类有而且只能有一个析构函数。析构函数不能重载。

6.什么是默认构造函数和默认析构函数?

假如用户没有自己编写构造函数或析构函数,编译系统也会自动生成一个构造函数和析构函数,这就是默认的构造函数和析构函数,但是这两个函数没有任何参数,也不进行任何

操作。

7.什么是复制构造函数?它的功能和特点是什么?

复制构造函数是一种特殊的构造函数,它用来在已存在的对象基础上建立一个新对象。 复制构造函数的名称也和类名是一样的,但是它的形式参数,都是指向一个已经存在的对象,因此它的形式参数都是这种形式:“const 类名 &ob”,即是一个对象的引用。

8.什么是静态成员?静态成员的作用是什么? 9.如何对对象进行初始化?

对象的初始化都是通过构造函数进行的,只要在声明对象时,逐个添好构造函数的实参。

10.什么是友元?它的作用有哪些?什么是友元函数和友元类?

11.什么是this指针?它有何作用?

一个类可以同时有很多对象存在,许多不同的对象可以调用相同的成员函数,编译系统为了知道当前是那个对象在调用成员函数,因此定义了this指针,this指针其实就是指向当前对象的指针。

12.什么是类的作用域?对象的生存期有何不同?

类的作用域简称类域,它是指在类的定义中由一对花括号所括起来的部分,每一个类都具有相应的类域。类域中定义的变量不能使用auto,register和extern等修饰符,只能用static修饰符,函数也不能用extern修饰符。

所谓对象的生存期是指对象从被创建开始到被释放为止的时间,按生存期的不同对象可分为如下三种:

1、局部对象:当对象被定义时调用构造函数,该对象被创建,当程序退出定义该对象所在的函数体或程序块时,调用析构函数,释放该对象。

2、静态对象:当程序第一次执行所定义的静态对象时,该对象被创建,当程序结束时,该对象被释放。

3、全局对象:当程序开始时,调用构造函数创建该对象,当程序结束时调用析构函数释放该对象。

13.分析下列程序的运行结果。 程序1:

#include #include class CCounter {

private:

double m_value; public:

void SetValue(double v) { m_value=v;} double GetValue(); int GetNum(); };

double CCounter::GetValue() {

return sin(10.0*m_value); }

int CCounter:: GetNum() { return (int)m_value; } void main() {

CCounter sam; sam.SetValue(50.0);

cout<<\ cout<<\}

程序2:

#include #include class person {

int age;

char name[10]; public:

void init(int i, char *str)

{ age = i; strcpy(name, str); }

void display()

{ cout<

void main()

{ person demo;

demo.init(30, \ demo.display(); } 程序3:

#include #include class person { int age;

char *name; public: void init(int i, char *str)

{

int j;

j=strlen(str)+1; name=new char[j]; strcpy(name, str);

age = i; }

~person() { delete name;

cout<<\

}

void display()

{ cout<

void main()

{ person demo;

demo.init(30, \ demo.display(); }

程序4:

#include class CSam {

public:

static int m;

CSam() { m++; }

CSam( int n ) { m = n; }

static void testm() { m++; } };

int CSam::m =0; void main() {

CSam A; CSam B(3); A.testm();

CSam::testm();

cout<<\ }

14.定义一个描述学生基本情况的类,数据成员包括姓名、学号、C++、英语和数学成绩,成员函数包括输出数据、置姓名和学号、置3门课的成绩,求出总成绩和平均成绩。

#include #include class CStudentInfo { char stu_name[20]; char stu_id[10]; float C_score; float E_score; float M_score; public:

CStudentInfo(char *name, char *id)

{

strcpy(stu_name,name); strcpy(stu_id,id); C_score=E_score=M_score=0.00;

}

void Init(float score1, float score2,float score3) { C_score=score1; E_score=score2; M_score=score3;

}

float GetTotal() { return (C_score+E_score+M_score); }

float GetAvg()

{ return (C_score+E_score+M_score)/3; }

void Display() {

cout<<\

cout<<\Language:\ English:\<

is:\ }

};

void main()

{ CStudentInfo stu(\ float score1,score2,score3;

Mathmetics:\

Average

cout<<\ cin>>score1; cout<<\ cin>>score2; cout<<\

cin>>score3;

stu.Init(score1,score2,score3);

stu.Display(); }

15.设有一个描述坐标点的CPoint类,其私有变量x和y代表一个点的x、y坐标值。编写程序实现以下功能:利用构造函数传递参数,并设其默认参数值为60和75,利用成员函数display()输出这一默认的值;利用公有成员函数setpoint()将坐标值修改为(80,150),并利用成员函数输出修改后的坐标值。

16.以下是一个类的测试程序,给出类的定义,构造一个完整的程序。执行程序时的输出如下。输出结果:200-60=140 主函数为: void main() {

CTest c;

c.init(200, 60); c.print(); }

CTest类的构造如下: #include class CTest {

int x,y;

public: void init(int x0,int y0) };

17.设有一个类,其定义如下: #include class CSample

{

x=x0; y=y0; }

void print() {

cout<<\}

{

char *p1, *p2; public:

void init(char *s1, char *s2); void print()

{ cout<<\ void copy(CSample &one); void free(); };

成员函数init()是将s1和s2所指向的字符串分别送到p1和p2所指向的动态申请的内存空间中,函数copy将对象one中的两个字符串复制到当前的对象中,free()函数释放p1和p2所指向的动态分配的内存空间。设计一个完整的程序,包括完成这3个函数的定义和测试工作。

#include #include class CSample {

char *p1, *p2;

public:

void init(char *s1, char *s2);

void print() { cout<<\ } void copy(CSample &one); void free(); };

void CSample::init(char *s1, char *s2) {

p1=new char[strlen(s1)+1]; p2=new char[strlen(s2)+1]; strcpy(p1,s1); strcpy(p2,s2); }

void CSample::copy(CSample &one) {

if (this!=&one ) *this=one; }

void CSample::free() {

delete[] this->p1; delete[] this->p2; }

void main() {

CSample a,b;

a.init(\ a.print(); b.copy(a); b.print(); a.free(); }

本程序的设计是有问题的,最好是把new分配内存写在构造函数中!如此无法进行b.free()!因为对象b没有用new分配内存,因此不可以用delete运算符。

18.设有一个类,其定义如下:

#include class CArray

{ int nSizeOfInt; //整型数组的大小

int nNumOfInt; //整型数组中实际存放的元素个数 int nSizeOfFloat; //浮点数组的大小

int nNumOfFloat; //浮点数组中实际存放的元素个数 int *pInt; //指向整型数组,动态分配内存空间 float *pFloat; //指向浮点数组,动态分配内存空间 public:

CArray(int nIntSize=100, int nFloatSize=200); void put(int n); //将n加入到整型数组中

void put(float x); //将x加入到浮点数组中

int getInt(int index); //取整型数组中第index个元素,index从0开始 float getFloat(int index); //取浮点数组中第index个元素,index从0开始 ~CArray(); //析构函数,释放动态分配的内存空间 void print(); //分别输出整型数组和浮点数组中的所有元素 };构造完整的程序,包括类成员函数的定义和测试程序的设计。构造函数中的nIntSize 和nFloatSize分别表示整型数组和浮点数组的大小。

CArray::CArray(int nIntSize, int nFloatSize) {

nSizeOfInt=nIntSize;

pInt=new int[nSizeOfInt]; nSizeOfFloat=nFloatSize;

pFloat=new float[nSizeOfFloat]; nNumOfInt=0;nNumOfFloat=0; }

void CArray::put(int n) {

pInt[nNumOfInt++]=n; }

void CArray::put(float x) { pFloat[nNumOfFloat++]=x; }

int CArray::getInt(int index) {

if (index>=0 && index<=nNumOfInt)

return pInt[index];

}

float CArray::getFloat(int index) {

if (index>=0 && index<=nNumOfFloat) return pFloat[index]; }

CArray::~CArray() {

delete [] pFloat; delete [] pInt; }

void CArray::print() {

for( int i=0;i

cout<<'\\n';

for( int j=0;j

void main() { int a=10;

float x=10.5;

CArray MyArray(10,15); MyArray.put(a); MyArray.put(x); MyArray.put(a+1); MyArray.put(x+1); MyArray.put(a+2); MyArray.put(x+2); MyArray.print(); }

19.在一个程序中,实现如下要求: (1)构造函数重载;

(2)成员函数设置默认参数;

(5)使用不同的构造函数创建不同的对象。

#include #include class stud{ private:

int num;

char name[10]; char sex; public: stud() { num=10010;

strcpy(name,\ sex='F';

} stud(int n,char nam[ ],char s ) { num=n; strcpy(name, nam) ; sex=s; }

void display()

{ cout<<\ cout<<\ cout<<\ };

void main()

{ stud stud1; stud1.display();

stud stud2(10011,\ stud2.display(); }

2.2 继承和派生类

20.派生类是如何定义的?它有哪些特点? ⑴定义派生类的一般形式为:

class 派生类名:[引用权限] 基类名 { 派生类新增的数据成员

派生类新增的成员函数 };

⑵派生类继承了基类的所有数据成员和成员函数,并增加新的成员。

21.派生类的继承方式有哪些?它们各有哪些特点?

这是继承技术中比较关键的问题。 从基类继承来的成员的引用,不是简单地把基类的私有成员和公用成员直接作为派生类的私有成员和公用成员来使用,而要根据基类成员的“封装权限”和派生类声明的“引用权限”共同决定。

①当引用权限为public时,称为“公用派生类”。在公用派生类中,基类的public成员和protected成员仍然成为派生类中的public成员和protected成员;然而基类中的私有成员却成为了派生类中的“不可访问的成员”,不能被派生类使用。

②当引用权限为private时,称为“私有派生类”。在私有派生类中,基类的公用成员和保护成员成为了派生类中的私有成员,基类的私有成员成为派生类“不可访问的成员”。

③从以上两点可以看出,基类中的私有成员在派生类中都成为了“不可访问的成员” 。因此在继承中经常使用另外一种封装字protected,被protected封装的成员称为“保护成员”, 保护成员和私有成员相似,不能被外界引用,但它却可以被派生类的成员函数引用。

22.在定义派生类的过程中,如何对基类的数据成员进行初始化?

基类的数据成员初始化往往是通过基类的构造函数进行的,但是在么在建立派生类的对象时,是不会自动执行基类的构造函数,因而就会使基类中成员变量未初始化。所以在设计派生类的构造函数时,不仅要考虑派生类所增加的成员变量初始化,还应当考虑基类的成员变量初始化。在执行派生类的构造函数时,应当调用基类的构造函数。 因此考虑到基类成员变量初始化后,派生类的构造函数一般形式为: 派生类构造函数名(参数表):基类构造函数名(参数表)

例如:

student(int n,char nam[],char s,int a,char ad[] ):stud(n,nam,s) 其中,student类是stud的派生类。

23.在派生类中能否直接访问基类中的私有成员?在派生类中如何实现访问基类中的私有成员?

在派生类中是不能直接访问基类中的私有成员的,要在派生类中访问基类中的私有成员,只能通过基类所提供的public或protected封装的成员函数进行。

24.什么是虚基类?它的作用如何?

在声明派生类时,在基类的引用权限前面加上virtual,就将基类声明成了虚基类,即: class 派生类名:virtual [引用权限] 基类名

虚基类的引入主要是针对多重派生的,是为了消除派生类的二义性使用的。通过虚基类派生出来的新类,同一个成员变量在不同的派生类中都只有一个复制,当通过普通基类派生的新类,同一个成员变量,在不同的派生类中的副本是不一样的。

25.分析以下程序的结果。 程序一、

#include class A { private: int a, b; public:

A(int i, int j) {a=i; b=j;}

void Offset(int x, int y) { a+=x; b+=y; }

void Display() { cout<<'('<

};

class B:private A {

private:

int x, y; public:

B(int i, int j, int k, int l):A(i,j) { x=k; y=l; } void Display() { cout<

{ A::Display(); }

void main() { A e(1,2); e.Display(); B d(3,4,5,6); d.Move(); d.Display(); d.Show(); }

运行结果:

程序二、

#include class CRoot{ public:

int small; CRoot()

{small= 2; } CRoot(int n) { small = n;} void showsmall()

{ cout<<\};

class CDer1:public CRoot {

public:

CDer1(int m):CRoot(m) { } };

class CDer2:public CRoot {

public:

int small;

CDer2(int n=0) {small=n; } };

void main() { CRoot A; CDer1 B(3);

CDer2 C;

A.showsmall(); B.showsmall(); C.showsmall(); }

运行结果:

26.定义一个人员类CPerson,包括数据成员:姓名、编号、性别和用于输入/输出的成员函数。在此基础上派生出学生类CStudent(增加成绩)和教师类CTeacher(增加教龄),并实现对学生和教师信息的输入/输出。 #include

class CPerson //声明基类

{ protected: //基类保护成员

int ID; char name[10]; char sex; public: CPerson()

{

cout<<\请输入以下资料:\

cout<<\编号:\ cin>>ID; cout<<\姓名:\ cin>>name; cout<<\性别:\ cin>>sex; cout<

void output()

{

cout<<\编号:\ cout<<\姓名:\ cout<<\性别:\ } };

class CStudent:public CPerson {

private: float score; public:

CStudent()

{ cout<<\成绩:\ cin>>score; }

void output()

{ CPerson::output();

cout<<\成绩:\ } };

class CTeacher:public CPerson {

private: int age;

public:

CTeacher()

{ cout<<\年龄:\ cin>>age; }

void output()

{ CPerson::output();

cout<<\年龄:\ } };

void main()

{ CPerson person1; person1.output(); CStudent stu; stu.output();

CTeacher teacher; teacher.output();

}

27. 把定义平面直角坐标系上的一个点的类CPoint作为基类,派生出描述一条直线的类CLine,再派生出一个矩形类CRecto要求成员函数能求出两点间的距离、矩形的周长和面积 等。设计一个测试程序,并构造完整的程序。

#include #include

class CPoint //声明基类 { protected: int x0,y0; public:

CPoint(int a=0,int b=0) { x0=a;

y0=b;

}

void output()

{

cout<<\ cout<<\ } };

class CLine:public CPoint {

private: int x1,y1;

public: CLine(int x,int y, int u=0, int v=0):CPoint(x,y) { x1=u; y1=v; }

void output() { CPoint::output();

cout<<\ cout<<\ }

double length()

{

return (double)sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0) ); }

};

class CRect:public CPoint {

private: int x1,y1;

public:

CRect(int x,int y, int u=0, int v=0):CPoint(x,y) { x1=u; y1=v; } float length() };

{

return (float)(2*((x1-x0)+(y1-y0))); }

float area()

{

return (float)(x1-x0)*(y1-y0); }

void main()

{

CLine l(1,0,1,1);

cout<<\长度=\ CRect rect(0,1,4,10);

cout<<\周长=\ cout<<\面积=\ }

28. 定义一个字符串类CStrOne,包含一个存放字符串的数据成员,能够通过构造函数初始化字符串,通过成员函数显示字符串的内容。在此基础上派生出CStrTwo类,增加一个存放字符串的数据成员;并能通过派生类的构造函数传递参数,初始化两个字符串,通过成员函数进行两个字符串的合并以及输出。(字符串合并可使用标准库函数strcat,需要包含头 文件string.h)

#include #include class CStrOne { protected:

char *pstr; public: CStrOne( char str[ ]) { pstr=str; } void show()

{ cout<<\ } };

class CStrTwo:public CStrOne {

char *newpstr;

public: CStrTwo( char str1[ ],char str2[ ]):CStrOne(str1)

{ newpstr=str2; } void show()

{ cout<<\ cout<<\

}

void joint()

{ char temp[100];

strcpy(temp, pstr);

newpstr=strcat(temp,newpstr); cout<

void main() {

CStrTwo str(\ str.show(); str.joint(); }

2.3 多态和虚函数

29.什么是多态性?

所谓“多态性”就是不同对象收到相同的消息时,产生了不同的动作。这里的消息主要是指对类的成员函数的调用,因此的函数重载就是多态性的表现。

30.什么是虚函数?为什么要定义虚函数?

在函数的声明时,在函数名前面加上vitual就实现了虚函数的声明。通过虚函数和继承,可以实现运行时的多态性。即在程序执行前,根据函数和参数还无法确定应该调用哪一个函数,必须在程序的执行过程中,根据执行情况动态地确定。

31.什么是纯虚函数?什么是抽象类?

声明纯虚函数的一般格式为:

virtual 函数类型 函数名(形参表)=0;

它与一般虚函数不同的是:在纯虚函数的形参表后面多了个“=0”。把函数名赋于0,本质上是将指向函数的指针的初值赋为0,纯虚函数不能有具体的实现代码。

抽象类是指至少包含一个纯虚函数的特殊的类。它本身不能被实例化,也就是说不能声明一个抽象类的对象。必须通过继承得到派生类后,在派生类中定义了纯虚函数的具体的实现代码,才能获得一个派生类的对象。

32.分析下列程序的结果。 #include class B { public: B(){ }

B(int i) { b = i;}

virtual void virfun()

{ cout<<\ private: int b; };

class D: public B {

public: D(){}

D(int i, int j):B(i) {d=j;} private: int d;

void virfun() { cout<<\};

void fun(B *obj) { }

obj->virfun();

void main() {

D *pd = new D; fun(pd); }

33.定义一个抽象类CShape,包含纯虚函数Area()(用于计算面积)和SetData()(用于重设形状大小)。然后派生出三角形CTriangle类、矩形CRect类、圆CCircle类,分别求其面积。最后定义一个CArea类,计算这几个形状的面积之和,各形状的数据通过CArea类构造函数或成员函数来设置。编写一个完整的程序。 #include class CShape {

public:

virtual float Area()=0; virtual void SetData(float, float)=0; };

class CTriangle:public CShape {

private:

float l,h; public:

void SetData(float width=0, float height=0) { l=width; h=height; } float Area() };

class CRect:public CShape {

private: float w,h;

public:

void SetData(float width=0, float height=0) { w=width; h=height; }

float Area() { cout<< h*w<<'\\n'; { cout<< h*l/2<<'\\n'; return (h*l/2);

}

return (h*w); } };

class CCircle:public CShape {

private: float r;

public:

void SetData(float radius=0,float l=0) };

2.4运算符重载

34.运算符重载的含义是什么?是否所有的运算符都可以重载?

运算符重载也是实现静态多态性的一种方法,可以使操作的含义更加清晰。在C++中,

大多数系统预定义的运算符都能被重载,但是并不是所有的运算符都可以重载的,比如:

{ r=radius; } float Area()

{ cout<< 2*3.1416*r*r<<'\\n'; return (float)2*3.1416*r*r; }

? : :: .

就不能重载。

第3章 MFC基本应用程序的建立

1. Windows的应用程序特点有哪些?

参考书(p143~145)

2. MFC的AppWizard(exe)提供了哪几种类型的应用程序?

使用MFC的AppWizard可以创建下面三种类型的应用程序: (1)单文档界面的应用程序(SDI,single document interface); (2)多文档界面的应用程序(MDI,multiple documents interface); (3)基于对话框的应用程序(dialog based)。

3.MFC有哪些机制?这些机制有什么用?

4.用AppWizard创建一个多文档应用程序项目(MDI)Ex_MDIHello,比较MDI与SDI有哪些区别?

SDI应用程序由应用程序类(CWinApp)、框架窗口类(CFrameWnd)、文档类(CDocument)、视图类(CView)和文档模板类(CSinSleDocTemplate)共同作用。MDI应用程序与SDI应用程序的主要差别在于:MDI有CMDIFrameWnd和CMDIChildWnd两个框架窗口类,前一个派生

CMainFrame类,负责菜单等界面元素的主框架窗口管理;后一个派生CChildFrame类,负责相应的文档及其视图的子框架窗口维护。而SDI由框架窗口类CFrameWnd派生CMainFrame类。

5.消息的类别有哪些?用ClassWizard如何映射消息?

⑴窗口消息:窗口消息一般与创建窗口、绘制窗口、移动窗口和销毁窗口等操作相关。窗口消息的形式为WM_***,其中*的内容与每个窗口消息的内容有关。窗口消息只能被窗口或窗口对象处理,在MFC应用程序中,CView和CFrame及它们的派生类,以及自定义窗口类型都能处理窗口消息。 ⑵命令消息:命令消息一般与处理用户的某个请求或执行用户的某个命令相关。在MFC应用中,凡是从基类CCmdTarget派生的类都能处理命令消息,不仅窗口类CView、CFrame,而且文档类、应用程序类都可处理命令消息。一般通过选择菜单项、单击工具栏按钮、按加速键可产生命令消息。

⑶控件消息:控件消息与控件窗口中某个事件的发生相关。如改变文本框控件窗口的内容时,有一个通知窗口内容发生变化的控件事件产生。当选择列表框控件的某个选项时,也有一个通知选项发生改变的控件事件发生。

6.如何通过ClassWizard添加一个类?

第4章 对话框及常用控件

1.什么是对话框?它分为哪两类?这两类对话框有哪些不同?

对话框是CDialog类的派生类,它的主要功能是输出信息和接收用户的输入。对话框是一个特殊类型的窗口,任何对窗口的操作都可以在对话框中进行。对话框与控件是密不可分的,在每个对话框内一般都有一些控件,对话框依靠这些控件与用户进行交互。

对话框可以分为两种类型:一是模式对话框;二是无模式对话框。 ⑴模式对话框:所谓的模式对话框是指对话框弹出时,用户必须向对话框进行相应的操作,在退出对话框之前,其所在的应用程序是不能往下执行的。

⑵无模式对话框:无模式对话框是指对话框弹出后,一直保留在屏幕上,用户可以在对话框所在的应用程序中进行其他的操作。

两种对话框在编辑器设计和使用ClassWizard进行编程时方法基本一致,但在创建和退出对话框窗口时的方式不同。

在创建时,模式对话框是由系统自动分配内存空间,因此在对话框退出时,对话框对象 自动删除。而无模式对话框则需要用户来指定内存,退出时还要自己删除对话框对象。 在退出时,两种对话框所用的终止函数不一样。模式对话框通过调用CDialog::EndDialog来终止,而无模式对话框则是通过调用CWnd::DestroyWindow来终止。 需要说明的是:

由于函数CDialog::OnOK()和CDialog::OnCancel()是调用EndDialog的,因此无模式对话框必须用DestroyWindow来重载OnOK()和OnCancel()两个函数。另外,需要正确删除表示对话框的C++对象。

2.什么是对话框模板、对话框资源和对话框类?

⑴对话框模板:MFC Develop Studio提供的对话框模板是用来创建用户对话框资源,用对话框模板创建的基本界面上,包括一个OK(确定)按钮和一个Cancel(取消)按钮等。可以移动、修改、删除这些控件,或者是增加新的控件到对话框模板,构成应用程序所需的对话框资源。

⑵对话框资源:对话框资源是一个用户输入或取得数据的图形界面。这个图形界面是使用 对话框编辑器在对话框模板上创建的,程序员可以在对话框模板上增加并编辑控件,生成对话框资源。当应用程序运行时,就可以得到一个对话框。

⑶对话框对象

MFC使用CDialog类来描述对话框,它是CWnd类的派生类。在CWnd类的基础上增加了数据交换的功能。当创建一个新的对话框资源后,使用ClassWizard可以创建一个对话框类的派生类。对话框对象实现了对话框和应用程序之间的通信。在应用程序中定义一个对话框对象后,在对话框关闭后,可以通过访问对话框对象的成员变量获得用户的输入数据。

3.对一个对话框编程一般经过几个步骤?

⑴创建对话框资源;⑵增加控件并设置控件属性;⑶设计对话框类;⑷模式或非模式方式显示对话框

4.什么是控件?根据控件的性质可以将控件分为几类?

控件是系统内部定义的能完成特定功能的一些组件,控件能够放置在一个对话框中,提供应用程序与用户交互的某种功能的类,根据控件的特性和功能,一般可以将其分为3类:Windows通用控件、ActiveX控件以及MFC新增控件,Windows通用控件一般都是从CWnd派生而来的。

5.向对话框添加一个常用控件的方法有哪些?这些方法是否适用于ActiveX控件?

6.什么是DDV/DDX技术?如何使用这种技术?

为了能方便地操作一个控件,MFC采用了独特的DDX(Dynamic Data Exchange,动态数据交换)和DDV(Dynamic Data verify,动态数据交换)技术。DDX将数据成员变量与对话类模板内的控件相连接,这样使得数据在控件之间很容易传输。DDV用于数据的校验,它能自动校验数据成员变量数值的范围,并给出警告。

7.什么是控件的通知消息?它在编程中起哪些作用?

当控件状态发生改变时,控件就会向其父窗口发送消息,这就是控件的通知消息。控件的通知消息可以是一条WM_COMMAND消息,也可以是一条WM_NOTIFY消息。

8.什么是按钮控件?它有几种类型?

按钮控件是CButton类的控件。按钮控件分为:

⑴推压式按钮BS_PUSHBUTTON;⑵单选按钮BS_RADIOBUTTON;⑶复选按钮BS_CHECKBOX

9.什么是编辑框控件?它有哪些功能?

编辑框是一个允许用户从键盘输入数据和编辑文本的矩形窗口。编辑框属于CEdit类的“窗口控件”,可以获得输入焦点。

10.编辑框控件中的EN_CHANGE和EN_UPDATE通知消息有何异同? ? EN_CHANGE:在文本发生改变后产生。

? EN_UPDATE:在文本发生改变,还未显示之前产生。

11.向某一个应用程序添加一个对话框,并在对话框中添加一个按钮和一个编辑框,当单击按钮后,在编辑框中显示“你好!”字样。

12.什么是列表框和组合框?它们的通知消息有何异同?

列表框控件提供了文本项目的列表供用户选择,可以单选也可以多选。列表框是CListBox类的;组合框可以看成是编辑框和列表框的组合,它提供了列表框,允许用户从中选择项目;也提供了编辑框,允许用户直接输入,它是CCombobox类的。

这两个控件发送的都是通知消息(WM_NOTIFY)。当列表框中发生了某个动作,比如双击了列表框中某项时,列表框就会向其父窗口发送一条通知消息;而在组合框的通知消息中,有的是列表框发出的,有的是编辑框发出的。

13.在例[Ex_CommCtrls]的CListBoxDlg对话框中,如果使登记的成绩是4门课程,则对话框中的控件应如何添加?代码应如何修改?

14.什么是滚动条、进展条、滑动条和旋转按钮控件?

⑴滚动条:是CSrollBar类的控件,它有一个独立的窗口,两端有两个箭头按钮,中间有一个可移动的滚动块 ,具有直接的输入焦点,分为垂直滚动条和水平滚动条两种类型。 ⑵进展条:用于说明一个操作的进度,在操作过程中不断地从左到右填充进展条,可以让用户看到还有多少任务要完成。

⑶滑动条:由滑动块和可选的刻度线组成的,它是CSliderCtrl 类的。

⑷旋转按钮控件:是CSpinButtonCtrl类的,由一对箭头按钮组成,它通常与一个相伴的控件一起使用。

15.什么是旋转按钮的“伙伴”控件?如何设置?

与旋转按钮控件一起使用的控件称为“伙伴(buddy)控件”, 单击旋转按钮控件的箭头按钮,可以增大或减小其伙伴控件中某个值。 伙伴(buddy)控件的设置有两种方法:

①SetBuddy:设置旋转控件的伙伴窗口。 ②在对话框中用Ctrl+D进行设置

16.在MFC中,通用对话框有哪些?如何在程序中使用它们?

Windows提供了一组标准用户界面对话框,它们都有相应的MFC库中的类来支持,所有这些通用对话框类都是从一个公共的基类CCommonDialog派生而来的。

MFC的涌用对话框

17.如果消息对话框只有“是”和“否”两个按钮,则如何设置MessageBox函数的参数?

答:可以将MessageBox函数中的参数nType设置为MB_YESNO。

第5章 菜单、工具栏和状态栏

1.菜单有哪些常见的规则? P221

为了使Windows程序更容易操作,菜单的显示都遵循下列一些规则:

⑴若单击某菜单项后,将弹出一个对话框,那么在该菜单项文本后有“?”。

⑵若某项菜单有子菜单,那么在该菜单项文本后有 。 ⑶若菜单项需要助记符,则用括号将带下画线的字母括起来。助记符与Alt构成一个组合键,当按住“Alt”键不放,再敲击该字母时,对应的菜单项就会被选中。

⑷若某项菜单需要快捷键的支持,则一般将其列在相应菜单项文本之后。

2.什么是助记符?它是如何在菜单中定义的? P221

菜单项的助记符是用括号和带下画线的字母括起来的符号,助记符与Alt构成一个组合键。

3.菜单项的消息有哪些?

菜单项产生的消息有:COMMAND 消息和UPDATE_COMMAND_UI消息。

4.若对同一个菜单用Class Wizard分别在视图类和主框架窗口类CMainFrame都处理其 COMMAND消息,并在它们的函数中添加相同的代码,则当用户选择该菜单后,会有什么

样的结果?为什么?

命令消息处理的优先级别为:命令→视图类→文档类→文档模板类→框架窗口类→应用程序类。因此,视图类的消息处理函数会执行,而

5.什么是键盘快捷键?它是如何定义的?

键盘快捷键也称为加速键,加速键一般是几个按键的组合,用于激活特定的命令。 用Ctrl+R进入资源编辑器,选择Accelerator的资源项,双击IDR_MAINFRAME,进

行加速键资源的添加。

6.什么是快捷菜单?用程序实现一般需要哪些步骤?

快捷菜单也称为浮动式弹出菜单,即按下鼠标右键时,就会相应地弹出一个菜单。 用CMenu::TrackPopupMenu和资源编辑器可以创建这样的菜单。具体操作步骤如下: ①用Ctrl+R进入资源编辑器,新建一个菜单资源;

②在视图类或其他接收鼠标右键单击的窗口类中添加WM_CONTEXTMENU消息控制函数;编辑代码如下:

CMenu menu; //菜单项目是属于CMenu类的 menu.LoadMenu(IDR_MENU1); //加载菜单资源 menu.GetSubMenu(0)->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);

7.如何使一个工具按钮和某菜单项命令相结合?

将工具栏上按钮的ID设置成和菜单项ID一样即可。

8.状态栏的作用是什么?状态栏的窗格分为几类?如何添加和减少相应的窗格? ⑴状态栏是一条位于应用程序的主窗口底部的水平条,可以分割成几个窗格,用来显示应用程序的当前状态信息或提示信息。

⑵状态栏窗格分为“信息行窗格”和“指示器窗口”。

⑶要增加一个信息行窗格,则只需在状态栏数组中适当的位置增加一个ID_SEPARATOR标识即可;要增加指示器窗格,则在状态栏数组的适当位置增加一个在“字符串表”中定义过的资源ID。若要减少窗格,只需减少数组元素即可。

9.如何在状态栏的窗格显示文本?

可以调用CStatusBar::SetPaneText函数更新任何窗格中的文本。

10.若状态栏只有一个用户定义的指示器窗格(其ID号为ID_TEXT_PANE),应如何定义?若当用户在客户区双击鼠标时,在该窗格中显示“双击鼠标”字样,则应如何编程? 答:步骤:

首先建立一个SDI应用程序,然后:

⑴用Ctrl+R进入资源编辑器,新建一个字符串资源,其ID为ID_TEXT_PANE;

⑵打开MainFrm.cpp文件,删除状态栏数组中缺省的元素,并增加一个为ID_TEXT_PANE的元素;

⑶为了使指示器窗格填满整个状态栏,可以在CMainFrame类的OnCreate函数中,添加以下代码:

m_wndStatusBar.SetPaneInfo(0,ID_TEXT_PANE,SBPS_STRETCH,0);

⑷将CMainFrame类的的成员变量m_wndStatusBar由protected类型改为public型;

⑸在SDI视图类中加入:

#include \

⑹用Ctrl+W进入类向导,在SDI视图类中映射WM_LBUTTONDBCLK的消息处理函数,并增加代码:

CMainFrame *pFrame=(CMainFrame *)AfxGetApp( )->m_pMainWnd; CStatusBar *pStatus=&pFrame->m_wndStatusBar; if (pStatus)

pStatus->SetPaneText(0,\双击鼠标\

11.什么是命令更新消息?它的作用是什么?

UPDATE_COMMAND_UI消息又称为“更新命令UI消息”,该消息映射函数中有一个CCmdUI类的对象pCmdUI,CCmdUI类中包含了一个指向菜单项或工具栏按钮的指针,于是利用该指针对菜单项或工具栏按钮的显示形式进修改。

第6章 框架窗口、文档和视图

1.什么是主窗口和文档窗口? ⑴主窗口又称为“主框架窗口”,是应用程序直接放置在桌面上的那个窗口,每个应用程序只能有一个主窗口,主框架窗口的标题栏上往往显示应用程序的名称。当用MFC 程序向导创建单文档SDI或多文档MDI应用程序时,主窗口类名是CMainFrame ,源文件名是MainFrm.h和MainFrm.cpp。

⑵文档窗口是CDocument类的派生类,只能出现在主窗口之内,即主窗口是文档窗口的工作平台。文档窗口可以包含一个文档或一个数据文件等。在一个主窗口中可同时打开几个文档窗口。

2.窗口的风格分为哪两类?各举一例。

窗口风格有一般风格(以WS_为前缀)和扩展风格(以WS_ EX_为前缀)两种形式。 例如: WS_ORDER表示窗口含有边框,WS_EX_MDICHILD 表示创建一个 MDI子窗口。

3.改变窗口风格的方法有哪些?

⑴在用MFC AppWizard创建SDI或MDI应用程序过程的第四步中进行设置; ⑵在CMainFrame类的PreCreateWindow函数中有个表示窗体的引用变量cs,利用它可以修改窗体的风格;

⑶使用ModifyStyle和ModifyStyleEx:它们都是CWnd类的成员函数,可以更改窗口的风格,ModifyStyleEx还可更改窗口的扩展风格。

4.窗口状态的改变方法有哪些?

⑴在应用程序类的InitInstance函数中,用ShowWindow改变窗口的显示状态; ⑵用CWnd类提供的成员函数SetWindowPos、MoveWindow、CenterWindow都可以改变窗口的显示状态;

5.若将主窗口的大小设置为屏幕的1/4大小,并移动到屏幕的右上角,应如何实现? 答:在CMainFrame类的PreCreateWindow函数中添加代码:

cs.cy= ::GetSystemMetrics(SM_CYSCREEN)/2;

cs.cx= ::GetSystemMetrics(SM_CXSCREEN)/2; cs.y=0; cs.x=(cs.cx*2-cs.cx);

6.若将多文档的文档窗口的大小设置为主窗口客户区的1/4大小,并移动到主窗口客户区的右上角,应如何实现?

答:在CMainFrame类的PreCreateWindow函数中添加代码: cs.cy= ::GetSystemMetrics(SM_CYFULLSCREEN)/2; cs.cx= ::GetSystemMetrics(SM_CXFULLSCREEN)/2; cs.y=0; cs.x=(cs.cx*2-cs.cx);

7.对于SDI应用程序来说,能否有多个文档类型?应如何实现?

对于SDI应用程序来说可以有多个文档类型,通过修改文档模板字串资源实现。

8.文档字串资源有哪些含义?如何编辑字串资源?

⑴文档模板字串资源用于标识文档类型、标题等内容的

⑵字串资源的每一项都是以“XXXX\\n”结构组成的,不同的位置有不同的含义,参考课件。

9.若想通过对文档字串资源的更改,使应用程序的“打开”或“保存”对话框中的文件类型显示为“C源文件(*.c,*.cpp)”,则应如何实现? 答:文档模板字串资源的合适位置插入以下字符串: ?? C源文件(*.c,*.cpp)\\n.c;*.cpp\\n ??

10.什么是文档的序列化?其过程是怎样的?

⑴ “序列化”的概念是说对象可以持续的,即当程序退出时它可存盘,而当程序重启动时它们又可恢复。对象的这种存盘和恢复处理过程就称为“序列化Serialize ”。 ⑵利用Serialize函数可以避免直接使用CFile对象,但是在Serialize函数与CFile对象之间,存在一个归档对象(CArchive类)。CArchive对象可以看成CFile对象的数据缓冲区,它具有一个内部标记,用来标识归档是存入(写盘)还是载入(读盘)。每次只能有一个活动的归档对象与磁盘文件相连。应用程序框架会自动创建CFile及CArchive对象,为CFile对象打开相应的磁盘文件,并且将相应的归档对象与文件相连。用户只要在Serialize函数中,将数据存到归档对象中或从归档对象中取出。

本文来源:https://www.bwwdw.com/article/s84p.html

Top