1
C++
函数中值的传递方式有哪几种
?
答:
C++
函数的三种传递方式为:值传递、指针传递和引用传递。
2
头文件的作用是什么
?
答:一、通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。
答:一、通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。
二、头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。
3
内存的分配方式的分配方式有几种
?
答 : 一、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量。
二、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
三、从堆上分配,亦称动态内存分配。程序在运行的时候用 malloc 或 new 申请任意多少的内存,程序员自己负责在何时用 free 或 delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
答 : 一、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量。
二、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
三、从堆上分配,亦称动态内存分配。程序在运行的时候用 malloc 或 new 申请任意多少的内存,程序员自己负责在何时用 free 或 delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
4
实现双向链表删除一个节点
P
,在节点
P
后插入一个节点,写出这两个函数
;
答:双向链表删除一个节点 P
template<class type> void list<type>::delnode(int p)
{
int k=1;
listnode<type> *ptr,*t;
ptr=first;
答:双向链表删除一个节点 P
template<class type> void list<type>::delnode(int p)
{
int k=1;
listnode<type> *ptr,*t;
ptr=first;
while(ptr->next!=NULL&&k!=p)
{
ptr=ptr->next;
k++;
}
t=ptr->next;
cout<<" 你已经将数据项 "<<t->data<<" 删除 "<<endl;
ptr->next=ptr->next->next;
length--;
delete t;
}
{
ptr=ptr->next;
k++;
}
t=ptr->next;
cout<<" 你已经将数据项 "<<t->data<<" 删除 "<<endl;
ptr->next=ptr->next->next;
length--;
delete t;
}
在节点
P
后插入一个节点:
template<class type> bool list<type>::insert(type t,int p)
{
listnode<type> *ptr;
ptr=first;
template<class type> bool list<type>::insert(type t,int p)
{
listnode<type> *ptr;
ptr=first;
int k=1;
while(ptr!=NULL&&k<p)
{
ptr=ptr->next;
k++;
}
if(ptr==NULL&&k!=p)
return false;
else
{
listnode<type> *tp;
tp=new listnode<type>;
tp->data=t;
tp->next=ptr->next;
ptr->next=tp;
length++;
return true;
}
}
while(ptr!=NULL&&k<p)
{
ptr=ptr->next;
k++;
}
if(ptr==NULL&&k!=p)
return false;
else
{
listnode<type> *tp;
tp=new listnode<type>;
tp->data=t;
tp->next=ptr->next;
ptr->next=tp;
length++;
return true;
}
}
5
写一个函数,将其中的
/t
都转换成
4
个空格。
void change(char* pstr)
{
while(*pstr++ != '/0')
{
if (*pstr == '/t')
}
}
void change(char* pstr)
{
while(*pstr++ != '/0')
{
if (*pstr == '/t')
}
}
6
如何定义和实现一个类的成员函数为回调函数?
答
:
把成员函数申明为
static
就可以了
.
7
C++
里面是不是所有的动作都是
main()
引起的?如果不是,请举例
.
答
:
当然不是的
.
并不是所有的动作都是由
main
()引起的,只是编译器是由
main()
开始执行的
静态变量和全局变量的分配早在
main
之前完成
内联,模板,宏的扩展全是编译期行为,也不是
main()
完成的
注
:C++
和
main()
逻辑上没有必然的联系
8
C++
里面如何声明
const void f(void)
函数为
C
程序中的库函数?
答
: extern "C" void f(void);
所以
extern "C"
是强迫
c++
编译器对函数名进行修饰的时候采用
c
命名约定。
这样,在 c++ 写的程序中就可以使用已经用 c 编译器编译好的 obj 或者 lib 了
这样,在 c++ 写的程序中就可以使用已经用 c 编译器编译好的 obj 或者 lib 了
9
Windows
程序的入口是哪里?写出
Windows
消息机制的流程
.
答
:
入口点是
WinMain
函数
.
Windows
消息机制的流程
:
一 Windows中有一个系统消息队列,对于每一个正在执行的Windows应用程序,系统为其建立一个“消息队列”,即应用程序队列,用来存放该程序可能 创建的各种窗口的消息。应用程序中含有一段称作“消息循环”的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。
二 Windows为当前执行的每个Windows程序维护一个「消息队列」。在发生输入事件之后,Windows将事件转换为一个「消息」并将消息放入程序的消息队列中。程序通过执行一块称之为「消息循环」的程序代码从消息队列中取出消息:
while(GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
while(GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
TranslateMessage(&msg); 将msg结构传给Windows,进行一些键盘转换。
DispatchMessage (&msg); 又将msg结构回传给Windows。然后,Windows将该消息发送给适当的窗口消息处理程序,让它进行处理
DispatchMessage (&msg); 又将msg结构回传给Windows。然后,Windows将该消息发送给适当的窗口消息处理程序,让它进行处理
SendMessage()与PostMessage()之间的区别是什么?
它们两者是用于向应用程序发送消息的。PostMessagex()将消息直接加入到应用程序的消息队列中,不等程序返回就退出;而SendMessage()则刚好相反,应用程序处理完此消息后,它才返回
它们两者是用于向应用程序发送消息的。PostMessagex()将消息直接加入到应用程序的消息队列中,不等程序返回就退出;而SendMessage()则刚好相反,应用程序处理完此消息后,它才返回
10
把一个链表反向填空
void reverse(test* head)
{
test* pe = head;
test* ps = head->next;
while(ps)
{
pe->next = ps->next;
ps->next = head;
head = ps;
ps = pe->next;
}
}
11 什么函数不能成为虚函数 ?
void reverse(test* head)
{
test* pe = head;
test* ps = head->next;
while(ps)
{
pe->next = ps->next;
ps->next = head;
head = ps;
ps = pe->next;
}
}
11 什么函数不能成为虚函数 ?
构造函数
内联函数
(
因为没有函数地址
,
在编译时插入
,
是个静态行为
)
静态成员函数
(
因为
:
静态成员函数类似于全局函数,不过是属于相应类的
,
在相应类的作用域下,没有 this 指针 )
在相应类的作用域下,没有 this 指针 )
12
虚函数与接口的区别
:
答
::
虚函数的概念:
虚函数是动态联编的基础,它是引入派生概念之后用来表现基类和派生类成员函数之间的一种关系的。虚函数在基类中定义,它也是一种成员函数,而且是非静态成员函数。
若一个实例方法的声明中含有 virtual 修饰符,则称该方法为虚拟方法;一个虚拟方法的实现可以由派生类取代。取代所继承的虚拟方法的实现的过程称为重写 ( 覆盖 ) 该方法;在一个虚拟方法调用中,该调用所涉及的那个实例的运行时类型确定了要被调用的究竟是该方法的哪一个实现。
虚函数的限制:
1). 虚函数仅适用于有继承关系的类对象 , 所以只有类的成员函数才能说明 为虚函数 .
2). 静态成员函数不能是虚函数 .
3). 内联函数不能是虚函数 .
4) 构造函数不能是虚函数 .
5). 析构函数可以是虚函数 .
接口可以有静态成员、嵌套类型、抽象、虚拟成员、属性和事件。实现接口的任何类都必须提供接口中所声明的抽象成员的定义。接口可以要求任何实现类必须实现一个或多个其他接口。
对接口有以下限制:
接口可以用任何可访问性来声明,但接口成员必须全都具有公共可访问性。
不能向成员或接口自身附加安全性权限。
接口可以定义类构造函数,但不能定义实例构造函数。
每种语言都必须为需要成员的接口映射一个实现提供规则,因为不只一个接口可以用相同的签名声明成员,且这些成员可以有单独的实现。
接口可以由类和结构来实现。为了指示类或结构实现了某接口,在该类或结构的基类列表中应该包含该接口的标识符。如果一个类或结构实现某接口,则它还隐式实现该接口的所有基接口。即使在类或结构的基类列表中没有显式列出所有基接口,也是这样。
虚函数是动态联编的基础,它是引入派生概念之后用来表现基类和派生类成员函数之间的一种关系的。虚函数在基类中定义,它也是一种成员函数,而且是非静态成员函数。
若一个实例方法的声明中含有 virtual 修饰符,则称该方法为虚拟方法;一个虚拟方法的实现可以由派生类取代。取代所继承的虚拟方法的实现的过程称为重写 ( 覆盖 ) 该方法;在一个虚拟方法调用中,该调用所涉及的那个实例的运行时类型确定了要被调用的究竟是该方法的哪一个实现。
虚函数的限制:
1). 虚函数仅适用于有继承关系的类对象 , 所以只有类的成员函数才能说明 为虚函数 .
2). 静态成员函数不能是虚函数 .
3). 内联函数不能是虚函数 .
4) 构造函数不能是虚函数 .
5). 析构函数可以是虚函数 .
接口可以有静态成员、嵌套类型、抽象、虚拟成员、属性和事件。实现接口的任何类都必须提供接口中所声明的抽象成员的定义。接口可以要求任何实现类必须实现一个或多个其他接口。
对接口有以下限制:
接口可以用任何可访问性来声明,但接口成员必须全都具有公共可访问性。
不能向成员或接口自身附加安全性权限。
接口可以定义类构造函数,但不能定义实例构造函数。
每种语言都必须为需要成员的接口映射一个实现提供规则,因为不只一个接口可以用相同的签名声明成员,且这些成员可以有单独的实现。
接口可以由类和结构来实现。为了指示类或结构实现了某接口,在该类或结构的基类列表中应该包含该接口的标识符。如果一个类或结构实现某接口,则它还隐式实现该接口的所有基接口。即使在类或结构的基类列表中没有显式列出所有基接口,也是这样。
13 C
++
中虚函数怎么实现的
?
答
:
每个定义了虚函数的类都有一张虚函数表
vtbl
(
virtual funtion table
),这张表实际上是一个函数指针的数组,记录了虚函数的入口地址。只要这个类有虚函数,不管是自己定义的还是从父类继承过来的,那么类的每个实例——对象都一个指针
vptr
(
virtual function table pointer
),它指向类的虚函数表。
虚函数
(
多态
)
机制的三个条件
:
1 派生关系
2 virtual 属性
3 指针 -> 访问方式
1 派生关系
2 virtual 属性
3 指针 -> 访问方式