这是我在别人的帖子提问的回复看到的30个问题,感觉有些问题不太明白,请大家给指导一下:
1。namespace是做什么用的?
2。现在需要一个指针,这个指针指向某个类的某个非静态成员函数,C++怎么声明这个指针?怎么对其赋值?如果是指向非静态成员变量又如何?
3。为什么在switch语句中,如果在某个case下面写int i=1;会出错,而写成int i; i=1;却会编译通过?
4。386+ CPU中的通用寄存器有eax、ebx、ecx、edx、esi、edi、esp和ebp。调用Windows API时,这其中哪几个寄存器的值不会被修改?
5。某些成员函数的声明后往往加有const,这是什么意思?
6。为什么在使用类对象作为函数参数时,往往选择使用引用或指针,而不是像简单变量那样直接传值?
7。为什么构造函数不能重载,而析构函数往往都是虚函数?
8。类B和类C都是由类A继承而来,而类D是由类B和类C双重继承而来。那么类D的实例中将有几个类A的实例?如果有两个,现在要引用其中一个,C++如何表达?
9。什么叫upcast,什么叫downcast?什么叫RTTI?试着写一个程序用到typeid、static_cast、dynamic_cast这些C++运算符。
10。MFC的RTTI与标准C++的RTTI实现有什么不同?CRuntimeClass是做什么用的?
11。VC中C++标准的try-catch语法与微软扩展的__try、__except、__finally语法有什么不一样?使用异常处理的C++反汇编代码中经常有“mov eax, fs:[0]”这样的语句,那么fs:[0]处是什么东西?与异常处理有什么关系?
12。SEH是怎么实现的?现在Windows平台下的C++编译器实现try-catch时是否用到了SEH?
13。MFC程序的流程如何?程序从CRT的_WinMainCRTStartup开始执行后,是怎么跳到最后的CWinApp::InitInstance、CWinApp::Run的?
14。请仔细阅读MFC关于窗口创建部分的代码,MFC为什么要在窗口创建时安装一个WH_CBT类型的钩子?MFC是怎么对消息处理的?窗口过程是如何将一个消息发送到某个C++类的成员函数这里的?为什么像CDocument这样的类,并没有任何窗口与之关联,依然能收到WM_COMMAND之类的消息?
15。为什么CSocket不能在线程之间传递?还有哪些MFC类不能在线程之间传递?
16。你现在有一个工程,你希望拿到别的机器上继续开发,那么只需要将工程目录下的哪些文件复制即可?你想开发一个程序,使其可以脱离MFC和CRT的运行时动态链接库独立运行,你需要如何更改工程设置?你会使用VC的工具Dependency Walker检察某个可执行模块是否依赖于MFC和CRT动态链接库吗?
17。试着将#include "StdAfx.h"从cpp文件中去掉,如何修改工程设置,才可以使其依然照常编译?你用过Batch Build、Custom Build、Custom AppWizard这些功能吗?
18。利用嵌入汇编写一个__declspec(naked)的函数,使用stdcall调用规则,传入2个DWORD参数,并返回一个DWORD值。调用这个函数,希望不要出现堆栈错误。
19。什么叫内核对象?什么叫User对象?什么叫GDI对象?可以对一个GDI对象使用DuplicateHandle复制吗?User对象可不可以被子进程继承?
20。Windows是不是使用LDT来实现进程保护的?选择器、线性地址、虚拟地址、物理地址都是什么意思?写一个程序尝试分别使用LocalXXX/GlobalXXX、HeapXXX和VirtualXXX函数使用内存,它们有什么不同?
21。写一个Ping程序;写一个支持FTP与HTTP的下载程序。
22。做一个可以被VB调用的DLL。
23。利用Automation驱动Word打开一篇文档;利用ATL做一个ActiveX控件,可以在浏览器上显示当前系统时间。
24。利用CRecordset写一个操作Access数据库的程序。然后利用ADO写一个调用SQL Server存储过程的程序。
25。利用Multimedia API做一个简单的媒体播放机,可以播放CD、VCD、MP3等。
26。用Direct3D和OpenGL分别做一个旋转的正方体,当然,OpenGL版的最好做成屏幕保护程序。
27。分别写程序演示Windows 98下的Flat Thunk机制和NT下的General Thunk机制。
28。VC连接器生成的PE格式可执行文件都是以0x1000作为file alignment的。而Borland的连接器可以选择不同的file alignment。较小的file alignment可以缩小可执行文件的尺寸。Windows 98中,file alignment的最小合法值为512,而NT中还可以更小。写一个程序用来对编译好的PE执行文件的file alignment进行调整。当然,条件是这个程序依然能够正常执行。
29。写一段代码,实现在Windows 98下直接从Ring3跳入Ring0。
30。写一个程序,执行完后自己将自己从磁盘上删除
8.There are four instances of A in D. But if B and C virtually derive from A, there will be only one instance of A.
8
A
/ \
B C
\ /
D
假设:
class A {
protected:
int m_a;
};
讨论:
1、如果B, C的声明如下:
class B: public A {
...
};
class C: public A {
...
};
那么D类的实例中将有两个A类的实例。在D中引用m_a将导致一个不明确引用(ambiguous)编译错!
2、如果B, C的声明如下:
class B: virtual public A {
...
};
class C: virtual public A {
...
};
那么D类的实例中将只有一个A类的实例,因此在D中引用m_a是正确的!
14.1 请仔细阅读MFC关于窗口创建部分的代码,MFC为什么要在窗口创建时安装一个WH_CBT类型的钩子?
By Paul DiLascia
Paul DiLascia is the author of Windows ++: Writing Reusable Code in C++ (Addison-Wesley, 1992) and a freelance consultant and writer-at-large. He can be reached at askpd@pobox.com or http://pobox.com/~askpd.
-----------------------------------------------------------------
Before calling ::CreateWindowEx to create the window, MFC calls AfxHookWindowCreate; and after creating the window, it calls AfxUnhookWindowCreate. These functions set up and remove a WH_CBT (computer-based training) hook. A hook is an application callback function that Windows calls whenever certain events happen. There are several kinds of hooks; AfxHookWindowCreate uses a WH_CBT hook because, among other events, Windows calls it whenever creating or destroying a window.
MFC installs a hook function, _AfxCbtFilterHook, then sets a thread-global variable m_pWndInit, which points to the CWnd object being created or hooked. MFC uses a global because the Windows hook mechanism doesnt provide any way of passing an argument to the hook function.
So far, so good. Once the hook is set up, control passes into CWnd::CreateEx, which calls ::CreateWindowEx, a black box from MFCs point of view. Windows creates the window, la-di-dah. But immediately afterward, Windows looks at its internal structures, scratches its weary head, and says, "Oh, this app has a WH_CBT hook installed. Id better call the callback." So Windows calls _AfxCbtFilterHook, passing information about the window being created.
// simplified (!)
LRESULT _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (code != HCBT_CREATEWND)
// ignore
// subclass the window with AfxWndProc
CWnd* pWndInit = pThreadState->m_pWndInit;
pWndInit->Attach((HWND)wParam);
pWndInit->PreSubclassWindow(); // virtual
WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();
ASSERT(pOldWndProc != NULL);
WNDPROC afxWndProc = AfxGetAfxWndProc();
oldWndProc = (WNDPROC)SetWindowLong(hWnd,
GWL_WNDPROC, (DWORD)afxWndProc);
if (oldWndProc != afxWndProc)
*pOldWndProc = oldWndProc;
pThreadState->m_pWndInit = NULL;
return lResult;
}
_AfxCbtFilterHook attaches the HWND (sets m_hWnd) to the window object being created (pWndInit), then subclasses the window by installing the generic AfxWndProc. CWnd::GetSuperWndProcAddr returns an address where the old window proc can be saved.
After saving the old window proc, MFC calls PreSubclassWindow, another CWnd virtual function you can override if you want to do stuff just before the window is subclassed.
Finally, MFC installs AfxWndProc as the window proc. But actually, _AfxCbtFilterHook doesnt use AfxWndProc directly as the window proc; it calls a function AfxGetAfxWndProc to get the window proc.
WNDPROC AFXAPI AfxGetAfxWndProc()
{
#ifdef _AFXDLL
return AfxGetModuleState()->m_pfnAfxWndProc;
#else
return &AfxWndProc;
#endif
}
In a non-DLL app, AfxGetAfxWndProc simply returns AfxWndProc, but in a DLL the window proc is stored in the module state. Thats because the DLL must use the window proc of whichever application is calling it at any given time, not its own.
Once _AfxCbtFilterHook is finished, the window is hooked up. Control flows out of _AfxCbtFilterHook, out of the black box ::CreateWindowEx, and back to CWnd::CreateEx, which now calls AfxUnhookWindowCreate to remove the CBT hook. The raison detre of the CBT hook is to trap the windows creation so MFC can subclass the window—that is, install AfxWndProc.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Why does MFC go through such contortions? Why not just set the window proc in WNDCLASS::lpfnWndProc when the window class is registered, the way any Windows programmer who read Petzold would do it? Good question. There are two reasons. First, the install-a-hook method works for window classes that are not yours or MFCs—such as the built-in classes Button, ListBox, ToolbarWindow32, and so on—as well as window classes that belong to third-party libraries. OK, so why not just call SetWindowLong to subclass the window (change the window proc) after the window is created? Because—and this is the real reason MFC must set a hook—in that case your window object would never get a chance to handle WM_CREATE and WM_NCCREATE. These messages are sent by Windows itself, from within ::CreateWindowEx when Windows is creating the window.
Remember when I said ::CreateWindowEx is a black box to MFC? Once MFC calls CreateWindowEx, it can only wait until control returns. So in order to handle messages like WM_NCCREATE, MFC must hook up your window before it calls CreateWindowEx. But how can MFC do that when it doesnt know the HWND until CreateWindowEx returns. The only way out of this conundrum is to set a hook. Windows calls the CBT hook after its created the window (so the hook function gets a valid HWND), but before it sends any messages to the window proc. Whew!
If youre still with me, relax. The hard part is over. Earlier I said that there are two ways MFC can subclass a window. The first is when you call some Create function as described previously; the second happens when you call SubclassWindow or SubclassDlgItem. Fortunately, things are much simpler in this case because the window already exists. SubclassWindow and SubclassDlgItem subclass the window directly by calling ::SetWindowLong with GWL_WNDPROC, without using any hook subterfuge.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14.2MFC是怎么对消息处理的?窗口过程是如何将一个消息发送到某个C++类的成员函数这里的?为什么像CDocument这样的类,并没有任何窗口与之关联,依然能收到WM_COMMAND之类的消息?
In traditional programs for Windows, Windows messages are handled in a large switch statement in a window procedure. MFC instead uses message maps to map direct messages to distinct class member functions. Message maps are more efficient than virtual functions for this purpose, and they allow messages to be handled by the most appropriate C++ object?application, document, view, and so on. You can map a single message or a range of messages, command IDs, or control IDs.
这些问题我也问过:
15:yokishiro回答:
因为MFC很多类,都是线程安全的,你不能传递类的指针
对于CSocket,可以使用CSocket的Detach()获得SOCKET s,也可以直接从m_hSocket成员变量获得,但是一定要使用Detach(),这样你delete CSocket之后套接口描述字还是有效的,然后将这个套接口描述字传递给其他线程,在新线程中,newsocket, 并Detach(),然后将你传递的套接口描述字newsocket.Attach(s)。
你就可以在新县城中继续使用了
duiduiblues回答:
1.namespace即命名空间,其作用是使不同空间内的类等类型可以命名相同,而使用起来不会发生混淆等。
2.假设该函数原型为static unsigned long Process(void *&p);则可声明指针形式如下:unsigned long (*func)(void *&);赋值时可以如下:func = Process;注意:指向的函数必须为静态,同时还要注意__stdcall和__cdel的问题。
3.msdn上的原文:
It is illegal to jump past a declaration with an initializer unless the declaration is enclosed in a block.
The scope of the initialized variable lasts until the end of the switch statement unless it is declared in an enclosed block within the switch statement.
但如果没有default,上述问题不存在。
4.无论是数据寄存器、变址寄存器还是堆栈指针都会被改变。
5.表示此函数不改变他使用的对象的值。
6.函数参数值传递时,函数体首先会对参数进行拷贝。因此,若传递类对象本身,则拷贝数据过大;使用引用则使得函数体内可以直接修改类中成员;使用指针,拷贝的也只是个指针。
7.构造函数是内联inline的,不能作为虚函数。另外,声明为虚函数没有意义啊,难道其派生类能与基类同名吗?
8.1个
9.
10.只是一些扩展而已。CRuntimeClass是伴随着很多CObject扩展类的对象,使用DECLARE_DYNAMIC等几个宏引入。用于维护mfc派生类的类型等信息。
11、
__try Begins a guarded body of code. Used with the __except keyword to construct an exception handler, or with the __finally keyword to construct a termination handler.
__except Begins a block of code that is executed only when an exception occurs within its associated __try block.
__finally Begins a block of code that is executed whenever the flow of control leaves its associated __try block.
__leave Allows for immediate termination of the __try block without causing abnormal termination and its performance penalty.
fs是一个段寄存器
12、windows如何实现Structured Exception Handling不清楚。try\catch中应该使用了SEH提供的异常诊断机制。
13、winmaincrtstartup->winmain->afxwinmain->{afxbeginthread->InitInstance->Run}
14.mfc为窗口控制加了许多内在的机制。在文档试图模型中,docmanager为文档类和窗口类建立了一些映射关系。
15.CSocket类内建了一个窗口,使用了窗口的消息循环。
16、.h,.c,.cpp,.dsp,.rc, not using MFC,察看是否用mfc42.dll,mfvcrt.dll
17.not using precompiled headers
zhishao回答:
3题:
initialization of identifier is skipped by default label
The specified identifier initialization can be skipped in a switch statement.
It is illegal to jump past a declaration with an initializer unless the declaration is enclosed in a block.
The scope of the initialized variable lasts until the end of the switch statement unless it is declared in an enclosed block within the switch statement.
The following is an example of this error:
void func( void )
{
int x;
switch (x)
{
case 0 :
int i = 1; // error, skipped by default
{ int j = 1; } // OK, initialized in enclosing block
default :
int k = 1; // OK, initialization not skipped
}
}
请看:http://www.csdn.net/expert/topic/806/806312.xml?temp=4.694766E-02
1、大家都知道把。
2、typedef BOOL (Class::*fnMemberFunction)(void);
fnMemberFunction fn=&A::DoSomething;
3、看msdn把。
4、因为WINAPI是__stdcall,所以堆栈指针不会变。
5、简单。
6、效率高。
7、构造函数无法是虚函数,因为vtable在构造函数中才建立出来。
8、两个。B::A,C::A
9、在C++的一些书里面都有详细描述。
10、MFC用RUNTIMECLASS的一套宏来实现的dynamic_cast,我猜想MS做MFC的时候C++标准还没有支持RTTI。
11、前者是C++的exception,后者是SEH。
12、SEH信息块的地址。
13、链表实现;用到了。
14、不清楚,有人说是将window的handle和CWnd*映射起来。
15、CSocket使用了窗口,而窗口属于线程,传递会有问题。
16、用过vc的同志们都知道了。
17、更改pch为auto pch或者not pch。precompiled headers。
18、注意最后弹出参数stack。
19、只有内核对象能被继承,其他定义请看msdn。
20、这个要解释一天也解释不完。
21、vc samples都有吧。
22、不知道vb跟其他程序有什么不一样。
23、这个很简单,好像vc samples里面也有例子。
24-28,自己找例子吧。
29、看看PE的结构,应该很容易。
30、
#include <windows.h>
int main(void)
{
HMODULE module = GetModuleHandle(0);
CHAR buf[MAX_PATH];
GetModuleFileName(module, buf, sizeof buf);
CloseHandle(HANDLE(4));
__asm {
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
ret
}
return 0;
}
faint,11和12应该合在一起。13是回答的12。4应该是都会变,我忘了__stdcall是called出参数stack了。
1。namespace是做什么用的?
名字空间,比如你可以定义
typedef std::reverse_iterator<iterator> reverse_iterator;
然后在你的源文件里使用using namespace std;
如果这样的情况下你定义了变量reverse_iterator it;编译器会现在local的范围(就是当前类)里查找reverse_iterator,结果没有找到,然后到你定义的namespace std中找,结果找到了,
如果不写using ...那一句,编译器会到全局空间里去找.
2。现在需要一个指针,这个指针指向某个类的某个非静态成员函数,C++怎么声明这个指针?怎么对其赋值?如果是指向非静态成员变量又如何?
class AAA
{
public:
BOOL myfun(LPCTSTR);
}
操作非静态函数的指针
typedef BOOL (AAA::*PMYFUN)(LPCTSTR);
...
AAA aaa;
PMYFUN pMyfun;
pMyfun = &AAA::myfun;
可以参看msdn C2475
指向静态的成员变量就不用说了吧,简单的数据指针
3。为什么在switch语句中,如果在某个case下面写int i=1;会出错,而写成int i; i=1;却会编译通过?
我用的vs7,都可以通过编译
4。386+ CPU中的通用寄存器有eax、ebx、ecx、edx、esi、edi、esp和ebp。调用Windows API时,这其中哪几个寄存器的值不会被修改?
这可说不准,不过api返回以后都会检测esp是否改变,如果改变就会抛出一个异常,所以,应该说esp不不会变的
5。某些成员函数的声明后往往加有const,这是什么意思?
返回值是一个常量,不允许改变,不过中间还有细微的差别,比较典型的是char* const AAA();和const char* AAA();
前者的内容是常量,后者是常量指针
6。为什么在使用类对象作为函数参数时,往往选择使用引用或指针,而不是像简单变量那样直接传值?
减少拷贝,提高效率
7。为什么构造函数不能重载,而析构函数往往都是虚函数?
析构函数设置为虚是比较必要的,因为正常析构应该取决于类的真正的类型,比如你调用delete p;是,不管p现在是什么类型(某种基类)的对象,对应该是调用它自己的析构函数
8。1
9。保证类型转换的安全性,应该是运行时保证安全,但我从来不用
10。MFC的RTTI与标准C++的RTTI实现有什么不同?CRuntimeClass是做什么用的?
运行时刻库,典型的应用是在运行时判断某个指针的类型(iskindof(class))
13。MFC程序的 流程如何?程序从CRT的_WinMainCRTStartup开始执行后,是怎么跳到最后的CWinApp::InitInstance、CWinApp::Run的?
_WinMainCRTStartup->AfxWinMain里是如下代码
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
15。为什么CSocket不能在线程之间传递?还有哪些MFC类不能在线程之间传递?
因为他们没有做异步 处理,你自己加上异步处理,或者保证没有争用的话,也可以在多个线程 下用,不过有时在debug下有断言错
16。你现在有一个工程,你希望拿到别的机器上继续开发,那么只需要将工程目录下的哪些文件复制即可?你想开发一个程序,使其可以脱离MFC和CRT的运行时动态链接库独立运行,你需要如何更改工程设置?你会使用VC的工具Dependency Walker检察某个可执行模块是否依赖于MFC和CRT动态链接库吗?
把目录都copy过去不就完了?
可以把编译模式设置成静态包含
看依赖可以用命令行的dumpbin
dumpbin /dependents test.exe
可以看test.exe依赖于那些dll,也可以看dll
17。试着将#include "StdAfx.h"从cpp文件中去掉,如何修改工程设置,才可以使其依然照常编译?你用过Batch Build、Custom Build、Custom AppWizard这些功能吗?
第一问,没试过,
但是Batch Build确实很好用,现在我的项目有10个左右的项目,每个项目至少有两个版本,有的有5个以上的版本,可以一下全部编译,然后一个批处理就更新了安装宝
21。写一个Ping程序;写一个支持FTP与HTTP的下载程序。
例子很多
22。做一个可以被VB调用的DLL。
一般做成regular dll,引出函数定义成extern "C" WINAPI TYPE myfun(TYPE1)这样的样子,然后传递参数当然不能传CString之类的参数,只能传windows类型
29。写一段代码,实现在Windows 98下直接从Ring3跳入Ring0。
Ring0权限的取得
http://nfans.net/article/manu/37.html
30。写一个程序,执行完后自己将自己从磁盘上删除
下载http://www.jiangmin.com/update/kvup.exe,然后到kvup里把pe文件尾巴上的0作点改动,运行kvup,完了以后再看,kvup又回到原来的内容了.
5. const 表示不能修改类中的数据成员
8. 用virtual就可以实现一个了
9. RTTI是实时类型系统
5。某些成员函数的声明后往往加有const,这是什么意思?
const放在函数名的后面是保证函数中的参数不会遭到修改。
__try Begins a guarded body of code. Used with the __except keyword to construct an exception handler, or with the __finally keyword to construct a termination handler.
__except Begins a block of code that is executed only when an exception occurs within its associated __try block.
__finally Begins a block of code that is executed whenever the flow of control leaves its associated __try block.
__leave Allows for immediate termination of the __try block without causing abnormal termination and its performance penalty.