孙鑫VC++深入详解视频勘误和说明.docx
- 文档编号:9354210
- 上传时间:2023-02-04
- 格式:DOCX
- 页数:9
- 大小:17.32KB
孙鑫VC++深入详解视频勘误和说明.docx
《孙鑫VC++深入详解视频勘误和说明.docx》由会员分享,可在线阅读,更多相关《孙鑫VC++深入详解视频勘误和说明.docx(9页珍藏版)》请在冰豆网上搜索。
孙鑫VC++深入详解视频勘误和说明
一、在视频Lesson2中,在介绍构造函数时,我说:
“构造函数最重要的作用是创建对象本身,对象内存的分配由构造函数来完成的”,这句话是错的,对象内存的分配和构造函数没有关系,对象内存的分配是由编译器来完成的,构造函数的作用是对对象本身做初始化工作,也就是给用户提供初始化类中成员变量的一种方式,在类对象有虚表的情况下,构造函数还对虚表进行初始化。
另外,我说:
“C++又规定,如果一个类没有提供任何的构造函数,则C++提供一个默认的构造函数(由C++编译器提供)”,这句话也是错误的,正确的是:
如果一个类中没有定义任何的构造函数,那么编译器只有在以下三种情况,才会提供默认的构造函数:
1、如果类有虚拟成员函数或者虚拟继承父类(即有虚拟基类)时;
2、如果类的基类有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数);
3、在类中的所有非静态的对象数据成员,它们对应的类中有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数)。
二、在视频Lesson4的Code中,画扇形用如下代码即可:
if(m_bDraw==TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
}
带边线的扇形用如下代码即可:
if(m_bDraw==TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.LineTo(m_ptOld);
m_ptOld=point;
}
三、在视频Lesson8中,关于在对话框上放置组合框的问题,我说“如果拖动的矩形较小,组合框的列表框部分将无法显示,此时也无法调整组合框的上下位置的大小了”。
实际上,组合框的上下位置还是可以调整的,调整的办法如下:
在对话框资源处于编辑状态时,将鼠标移动到组合框控件右边向下的箭头上,当鼠标变成上下箭头形状时,单击鼠标左键,此时可以看到举行框围绕着组合框。
将鼠标移动到该矩形框下端的蓝色小方块上,当鼠标变成上下箭头形状时,按住鼠标左键向下拖动,直到把组合框的下拉列表框范围拖动到合适的大小时松开鼠标左键。
四、在视频Lesson16的事件代码中,有一个问题,修改如下:
voidmain()
{
HANDLEhThread1;
HANDLEhThread2;
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//将CreateEvent()函数放置在这个位置
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
//g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//取消这个位置的CreateEvent()函数。
/*g_hEvent=CreateEvent(NULL,FALSE,FALSE,"tickets");
if(g_hEvent)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"onlyinstancecanrun!
"< return; } }*/ SetEvent(g_hEvent); Sleep(4000); CloseHandle(g_hEvent); } 原因: 如果在线程产生之后调用CreateEvent(),假如线程提前被操作系统调度,那么线程里的WaitForSingleObject等待的将是一个空的g_hEvent,在这种情况下,WaitForSingleObject将返回WAIT_FAILED。 这个问题可以通过在CreateEvent()函数前添加Sleep(10)的调用来查看。 五、在视频Lesson16的采用事件的多线程同步代码中,有一个问题: 在线程1和线程2的代码中,有下面一段: while(TRUE) { WaitForSingleObject(g_hEvent,INFINITE); if(tickets>0) { Sleep (1); cout<<"thread1sellticket: "< } else break; SetEvent(g_hEvent); } 这个代码有一个问题,当线程1或线程2卖完最后一张票时,调用SetEvent(g_hEvent);将事件对象设置为有信号状态,另一个线程等待到事件对象,开始执行代码,判断tickets不大于0,于是执行else语句下的break,退出循环,此时SetEvent(g_hEvent);就没有被执行,导致线程1或线程2一直等待,直到主线程终止运行,整个程序才退出。 应将SetEvent(g_hEvent);在if和else中分别调用,修改如下: DWORDWINAPIFun1Proc( LPVOIDlpParameter //threaddata ) { while(TRUE) { WaitForSingleObject(g_hEvent,INFINITE); // ResetEvent(g_hEvent); if(tickets>0) { Sleep (1); cout<<"thread1sellticket: "< SetEvent(g_hEvent); } else { SetEvent(g_hEvent); break; } } return0; } DWORDWINAPIFun2Proc( LPVOIDlpParameter //threaddata ) { while(TRUE) { WaitForSingleObject(g_hEvent,INFINITE); // ResetEvent(g_hEvent); if(tickets>0) { Sleep (1); cout<<"thread2sellticket: "< SetEvent(g_hEvent); } else { SetEvent(g_hEvent); break; } } return0; } 六、在视频Lesson16的采用关键代码段的多线程同步代码中,有一个问题: 在视频讲解过程中,在线程1和线程2的代码中,有下面一段: while(TRUE) { EnterCriticalSection(&g_cs); Sleep (1); if(tickets>0) { Sleep (1); cout<<"thread1sellticket: "< } else break; LeaveCriticalSection(&g_cs); } 这个代码有一个问题,当线程1或线程2卖完最后一张票时,释放对临界区对象的所有权后,另外一个线程进入关键代码段,判断tickets不大于0,执行else语句下的break,退出循环,于是LeaveCriticalSection(&g_cs);就没有执行,导致线程1或线程2一直等待,直到主线程终止运行,整个程序才退出。 应将LeaveCriticalSection(&g_cs);在if和else中分别调用,修改如下: DWORDWINAPIFun1Proc( LPVOIDlpParameter //threaddata ) { while(TRUE) { EnterCriticalSection(&g_cs); Sleep (1); if(tickets>0) { Sleep (1); cout<<"thread1sellticket: "< LeaveCriticalSection(&g_cs); } else { LeaveCriticalSection(&g_cs); break; } } return0; } DWORDWINAPIFun2Proc( LPVOIDlpParameter //threaddata ) { while(TRUE) { EnterCriticalSection(&g_cs); Sleep (1); if(tickets>0) { Sleep (1); cout<<"thread2sellticket: "< LeaveCriticalSection(&g_cs); } else { LeaveCriticalSection(&g_cs); break; } } return0; } 七、在视频Lesson16的Code中,Chat的函数代码,OnSock函数忘记释放内存了,可以在出错判断的地方以及将要返回的地方加释放内存的语句(delete[]wsabuf.buf)。 voidCChatDlg: : OnSock(WPARAMwParam,LPARAMlParam) { switch(LOWORD(lParam)) { caseFD_READ: WSABUFwsabuf; wsabuf.buf=newchar[200]; wsabuf.len=200; DWORDdwRead; DWORDdwFlag=0; SOCKADDR_INaddrFrom; intlen=sizeof(SOCKADDR); CStringstr; CStringstrTemp; HOSTENT*pHost; if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag, (SOCKADDR*)&addrFrom,&len,NULL,NULL)) { MessageBox("接收数据失败! "); delete[]wsabuf.buf;//这里加一句释放内存的语句 return; } pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET); //str.Format("%s说: %s",inet_ntoa(addrFrom.sin_addr),wsabuf.buf); str.Format("%s说: %s",pHost->h_name,wsabuf.buf); str+="\r\n"; GetDlgItemText(IDC_EDIT_RECV,strTemp); str+=strTemp; SetDlgItemText(IDC_EDIT_RECV,str); delete[]wsabuf.buf;//这里加一句释放内存的语句 break; } } 八、在视频Lesson17的剪贴板编程的代码中,有一个问题,修改如下: if(OpenClipboard()) { if(IsClipboardFormatAvailable(CF_TEXT)) { HANDLEhClip; char*pBuf; hClip=GetClipboardData(CF_TEXT); pBuf=(char*)GlobalLock(hClip); GlobalUnlock(hClip); SetDlgItemText(IDC_EDIT_RECV,pBuf); //CloseClipboard();//去掉这一句。 错误原因: 如果程序没有进入第二个if语句,那么剪贴板不会关闭。 } CloseClipboard();//在这里添加关闭剪贴板的操作。 } 九、在视频Lesson18中,在OnIntervalChanged()函数中的代码逻辑上有一些问题,原先的代码如下: voidCClockCtrl: : OnIntervalChanged() { //TODAddnotificationhandlercode if(m_interval<0||m_interval>6000) { m_interval=1000; } else { m_interval=m_interval/1000*1000; KillTimer (1); SetTimer(1,m_interval,NULL); BoundPropertyChanged(0x1); } SetModifiedFlag(); } 应该改为: voidCClockCtrl: : OnIntervalChanged() { //TODAddnotificationhandlercode if(m_interval<0||m_interval>6000) { m_interval=1000; } else { m_interval=m_interval/1000*1000; } KillTimer (1); SetTimer(1,m_interval,NULL); BoundPropertyChanged(0x1); SetModifiedFlag(); } 十、在视频Lesson2中,关于函数覆盖的讲解是不正确的,正确的请参看《VC++深入详解》一书的2.2.8小节。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 孙鑫 VC 深入 详解 视频 勘误 说明