孙鑫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的事件代码中,有一个问题,修改如下:
void main()
{
HANDLE hThread1;
HANDLE hThread2;
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<<"only instance can run!"<<endl;
   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<<"thread1 sell ticket : "<<tickets--<<endl;
  }
  else
   break;
  
SetEvent(g_hEvent);
}
这个代码有一个问题,当线程1或线程2卖完最后一张票时,调用SetEvent(g_hEvent);将事件对象设置为有信号状态,另一个线程等待到事件对象,开始执行代码,判断tickets不大于0,于是执行else语句下的break,退出循环,此时SetEvent(g_hEvent);就没有被执行,导致线程1或线程2一直等待,直到主线程终止运行,整个程序才退出。应将SetEvent(g_hEvent);在 if 和 else 中分别调用,修改如下:
DWORD WINAPI Fun1Proc(
  
     LPVOID lpParameter   // thread data
)
{
while(TRUE)
{
  WaitForSingleObject(g_hEvent,INFINITE);
//  ResetEvent(g_hEvent);
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread1 sell ticket : "<<tickets--<<endl;
   SetEvent(g_hEvent);
  }
  else
  {
   SetEvent(g_hEvent);
   break;
  }
}
return 0;
}
DWORD WINAPI Fun2Proc(
 
       LPVOID lpParameter   // thread data
)
{
while(TRUE)
{
  WaitForSingleObject(g_hEvent,INFINITE);
//  ResetEvent(g_hEvent);
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread2 sell ticket : "<<tickets--<<endl;
   SetEvent(g_hEvent);
  }
  else
  {
  
SetEvent(g_hEvent);
   break;
  }
}
return 0;
}
六、在视频Lesson16的采用关键代码段的多线程同步代码中,有一个问题:在视频讲解过程中,在线程1和线程2的代码中,有下面一段:
while(TRUE)
{
  EnterCriticalSection(&g_cs);
  Sleep(1);
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread1 sell ticket : "<<tickets--<<endl;
  }
  else
   break;
  
LeaveCriticalSection(&g_cs);
}
这个代码有一个问题,当线程1或线程2卖完最后一张票时,释放对临界区对象的所有权后,另外一个线程进入关键代码段,判断tickets不大于0,执行else语句下的break,退出循环,于是LeaveCriticalSection(&g_cs);就没有执行,导致线程1或线程2一直等待,直到主线程终止运行,整个程序才退出。应将LeaveCriticalSection(&g_cs);在 if 和 else 中分别调用,修改如下:
DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
while(TRUE)
{
  EnterCriticalSection(&g_cs);
  Sleep(1);
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread1 sell ticket : "<<tickets--<<endl;
  
LeaveCriticalSection(&g_cs);
  }
  else
  {
   LeaveCriticalSection(&g_cs);
   break;
  }
}

return 0;
}
DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
)
{

while(TRUE)
{
  EnterCriticalSection(&g_cs);
  Sleep(1);
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread2 sell ticket : "<<tickets--<<endl;
  
LeaveCriticalSection(&g_cs);
  }
  else
  {
    LeaveCriticalSection(&g_cs);
    break;
  }
}
return 0;
}
 
七、在视频Lesson16 的 Code 中,Chat 的函数代码, OnSock 函数忘记释放内存了,可以在出错判断的地方以及将要返回的地方加释放内存的语句 ( delete[] wsabuf.buf )。

void CChatDlg::OnSock(WPARAM wParam,LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_READ:
  WSABUF wsabuf;
  wsabuf.buf=new char[200];
  wsabuf.len=200;
  DWORD dwRead;
  DWORD dwFlag=0;
  SOCKADDR_IN addrFrom;
  int len=sizeof(SOCKADDR);
  CString str;
  CString strTemp;
  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))
  {
   HANDLE hClip;
   char *pBuf;
   hClip = GetClipboardData(CF_TEXT);
   pBuf = (char *)GlobalLock(hClip);
   GlobalUnlock(hClip);
   SetDlgItemText(IDC_EDIT_RECV, pBuf);
   //CloseClipboard();//去掉这一句。错误原因:如果程序没有进入第二个if语句,那么剪贴板不会关闭。

  }
   CloseClipboard();//在这里添加关闭剪贴板的操作。

}

九、在视频Lesson18中,在OnIntervalChanged()函数中的代码逻辑上有一些问题,原先的代码如下:
void CClockCtrl::OnIntervalChanged()
{
// TOD Add notification handler code
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();
}
应该改为:
void CClockCtrl::OnIntervalChanged()
{
// TOD Add notification handler code
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();
}
如果您发现书中或视频中有任何的错误,请到 http://www.sunxin.org/bbs/ 上提交错误信息。
 
代码转载自:https://pan.quark.cn/s/8ce4326d996e 对于在 CentOS 7 系统中修改网卡配置文件后无法使设置生效的情况,经过实践验证,可以通过使用 nmcli 命令来进行调整。完成修改之后,需要重新启动虚拟机以使更改生效,这样操作流程即告完成。如果设置仍然无法生效,则表明虚拟机在启动过程中所获取的 IP 地址配置并非针对 eth0,此时可以对其它网卡的配置文件进行修改或将其移除。在 CentOS 7 系统中,网络配置的管理机制与早期版本存在差异,主要体现为采用了 Network Manager 服务来负责网络接口的管理。在某些情形下,尽管修改了 `/etc/sysconfig/network-scripts` 目录下的 `ifcfg-eth0` 文件,但网络配置却未能即时生效。此类问题的发生通常源于 CentOS 7 采用了不同于以往的配置读取方法。接下来将具体阐述如何借助 nmcli 命令来处理这一挑战。 以 root 用户身份登录系统并打开终端界面。nmcli 是 Network Manager 提供的命令行界面工具,它支持在命令行环境下执行网络连接的建立、编辑、查询及管理任务。针对修改 eth0 网卡配置的需求,可以遵循以下步骤进行操作: 1. 导航至 `/etc/sysconfig/network-scripts` 目录: ``` cd /etc/sysconfig/network-scripts ``` 2. 检查该目录内是否存在 `ifcfg-eth0.bak` 文件,该备份文件可能是先前调整配置时遗留下来的,若存在可能造成冲突。若发现该文件,可以选择将其删除: ``` [root@localhost netw...
代码转载自:https://pan.quark.cn/s/46fd08fb879c 网管教程 从入门到精通软件篇 ★一。★详尽的xp修复控制台指令及其应用!!! 放入xp(2000)的光盘,安装时选择R,执行修复! Windows XP(涵盖 Windows 2000)的控制台指令是在系统遭遇某些意外状况时的一种极具效用的诊断、检测以及恢复系统功能的工具。笔者确实一直期望能够将这方面的指令进行归纳,此次由老范辛苦整理了这份极具价值的秘籍。 Bootcfg bootcfg 命令用于启动配置与故障恢复(对大多数计算机而言,即 boot.ini 文件)。 带有特定参数的 bootcfg 命令仅在运用故障恢复控制台时方可使用。能够在命令行界面下运用带有不同参数的 bootcfg 命令。 用法: bootcfg /default 设定默认引导选项。 bootcfg /add 向引导清单中增添 Windows 安装。 bootcfg /rebuild 重复整个 Windows 安装流程并让用户选择需添加的项目。 注意:运用 bootcfg /rebuild 之前,应先借助 bootcfg /copy 命令备份 boot.ini 文件。 bootcfg /scan 探查用于 Windows 安装的全部磁盘并展示结果。 注意:这些结果被静态存储,并用于当前会话。若在当前会话期间磁盘配置发生变动,为获取更新的探查结果,必须先重启计算机,然后再次探查磁盘。 bootcfg /list 列示引导清单中已有的项目。 bootcfg /disableredirect 在启动引导程序中禁用重定向。 bootcfg /redirect [ PortBaudRrate] |[ useBio...
代码下载链接: https://pan.quark.cn/s/fc524f791b68 AA制程,即Active Alignment,被理解为主动对准,是一种用于确定零部件装配中相对位置的方法。在摄像头封装阶段,涉及图像传感器、镜座、马达、镜头、线路板等多个部件的重复组装,而传统的封装设备如CSP及COB等,均是依据设备设定的参数进行零部件的移动装配,因而零部件的叠加误差会逐渐增大,最终在摄像头上表现为拍照最清晰的位置可能偏离画面中心、四边清晰度不均等现象。伴随智能手机其他高端电子产品的普及,摄像头模组的性能正日益受到重视。高分辨率、卓越的低光表现以及稳定视频输出是现代用户所期望的。在摄像头模组的制造环节,各部件的精准定位对成像质量具有决定性作用。因此,一种名为“AA制程”(Active Alignment)的前沿技术被开发出来,成为摄像头精密对准的核心技术。 AA制程,即Active Alignment,是一种在摄像头封装过程中应用的主动对准方法。该方法在多个组件装配阶段发挥作用,涵盖图像传感器、镜座、马达、镜头线路板等部件。传统的封装方式,例如CSP(Chip Scale Package)COB(Chip On Board),依赖于设备预设的参数进行组装,但随着组件数量的增加,误差也会累积,最终影响摄像头的表现。例如在成像质量上可能出现中心位置偏移、四角清晰度不一致等问题。 AA制程技术的核心在于实时监测与主动调整。在组装过程中,它借助先进的检测设备持续监控半成品的状态,并根据实时信息对组装部件进行精确修正,从而显著降低装配误差。通过这种技术,能够确保摄像头模组中各组件的相对位置准确无误,从而使得最终的成像效果更加稳定,特别是在中心区域四角的清晰度上...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值