首页 > 代码库 > C++面试题(三)

C++面试题(三)

1 什么是函数对象?有什么作用?

2 STL迭代器种类?

五类迭代器如下:

      (1)输入迭代器:只读,一次传递
       为输入迭代器预定义实现只有istream_iterator和istreambuf_iterator,用于从一个输入流istream中读取。一个输入迭代器仅能对它所选择的每个元素进行一次解析,它们只能向前移动。一个专门的构造函数定义了超越末尾的值。总是,输入迭代器可以对读操作的结果进行解析(对每个值仅解析一次),然后向前移动。
     (2)输出迭代器:只写,一次传递
       这是对输入迭代器的补充,不过是写操作而不是读操作。为输出迭代器的预定义实现只有ostream_iterator和ostreambuf_iterator,用于向一个输出流ostream写数据,还有一个一般较少使用的raw_storage_iterator。他们只能对每个写出的值进行一次解析,并且只能向前移动。对于输出迭代器来说,没有使用超越末尾的值来结束的概念。总之,输出迭代器可以对写操作的值进行解析(对每一个值仅解析一次),然后向前移动。
      (3)前向迭代器:多次读/写
       前向迭代器包含了输入和输出迭代器两者的功能,加上还可以多次解析一个迭代器指定的位置,因此可以对一个值进行多次读/写。顾名思义,前向迭代器只能向前移动。没有为前向迭代器预定义迭代器。
      (4)双向迭代器:operator--
       双向迭代器具有前向迭代器的全部功能。另外它还可以利用自减操作符operator--向后一次移动一个位置。由list容器中返回的迭代器都是双向的。
      (5)随机访问迭代器:类似于一个指针
       随机访问迭代器具有双向迭代器的所有功能,再加上一个指针所有的功能(一个指针就是一个随机访问迭代器),除了没有一种“空(null)”迭代器和空指针对应。基本上可以这样说,一个随机访问迭代器就像一个指针那样可以进行任何操作,包括使用操作符operator[]进行索引,加某个数值到一个指针就可以向前或者向后移动若干个位置,或者使用比较运算符在迭代器之间进行比较。

迭代器类别

说明

输入迭代器

从容器中读取元素。输入迭代器只能一次读入一个元素向前移动,输入迭代器只支持一遍算法,同一个输入迭代器不能两遍遍历一个序列

输出迭代器

向容器中写入元素。输出迭代器只能一次一个元素向前移动。输出迭代器只支持一遍算法,统一输出迭代器不能两次遍历一个序列

正向迭代器

组合输入迭代器和输出迭代器的功能,并保留在容器中的位置

双向迭代器

组合正向迭代器和逆向迭代器的功能,支持多遍算法

随机访问迭代器

组合双向迭代器的功能与直接访问容器中任何元素的功能,即可向前向后跳过任意个元素

 

迭代器的操作:

每种迭代器均可进行包括表中前一种迭代器可进行的操作。迭代器的操作本质上是通过重载运算符来实现的,迭代器支持何种操作和能够执行什么运算是由迭代器所重载的运算符来决定的。

 

迭代器类型 操作类型 说明

所有迭代器

p++

++p

后置自增迭代器

前置自增迭代器s‘s

输入迭代器

*p

p=p1

p==p1

p!=p1

复引用迭代器,作为右值

将一个迭代器赋给另一个迭代器

比较迭代器的相等性

比较迭代器的不等性

输出迭代器

*p

p=p1

复引用迭代器,作为左值

将一个迭代器赋给另一个迭代器

正向迭代器

提供输入输出迭代器的所有功能

 

双向迭代器

--p

p--

前置自减迭代器

后置自减迭代器

随机访问迭代器

p+=i

p-=i

p+i

p-i

p[i]

p<p1

p<=p1

p>p1

p>=p1

将迭代器递增i位

将迭代器递减i位

在p位加i位后的迭代器

在p位减i位后的迭代器

返回p位元素偏离i位的元素引用

如果迭代器p的位置在p1前,返回true,否则返回false

p的位置在p1的前面或同一位置时返回true,否则返回false

3 10进制和16进制转换

4 不用if,while,do-while,for,打印出所有大于0小于k的整数.函数原型void printLess(int k)

5  char(127<<1 +1)

6  volitale/explict 的用法

7  struct A {

char;

char;

short;

float;

double;

};

 

struct B {

char;

short;

float;

char;

double;

};

  sizeof(A) = 

  sizeof(B) =

8 数据库事物

9 保证应用程序只有一个实例

方法一:用Mutex互斥量来实现,内核对象,可以用来进程间互斥,但是此时不能取得已经启动的实例窗口局柄,因此无法激活已经启动的实例窗口

#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <wtypes.h>
 
int main()
{
 
    BOOL bExist = FALSE;
    HANDLE hMutex = ::CreateMutex(NULL,TRUE,L"一个唯一的名字");
 
    if (GetLastError() == ERROR_ALREADY_EXISTS)
    {
        bExist = TRUE;
    }
    if (hMutex)
    {
        ::ReleaseMutex(hMutex);
    }
    if(bExist)
    {
        return 0;
    }
    while(1)
    {
        std::cout<<"hello world";
    }
    getchar();
    return 0;
}

方法二
一般来说,使程序只运行一个实例的最简单的方法当然是使用FindWindow()查找主窗口,如果主窗口已经存在了,当然说明已经有一个实例运行了。代码如下:
// 这种方法有缺陷,窗口名字改变之后就再也找不到了,FindWindow()的参数ClassName和Caption比较难取得。
HWND hWnd = FindWindow(NULL, TEXT("SingleInstanceFW"));
if(IsWindow(hWnd))
{
 ::MessageBox(NULL, TEXT("已经有一个实例在运行了。"), TEXT("注意"), MB_OK);
 ::ShowWindow(hWnd, SW_NORMAL);     // 显示
 ::SetForegroundWindow(hWnd);       // 激活
 return FALSE;
}

方法三

这种方法相比上面两种方法,避免上面两种方法的缺点,通过SetProp()为程序主窗口设置一个特殊的Property,然后在启动时遍历所有的窗口,找出包含着个Property的窗口局柄

。【这个附加的窗口属性在窗口销毁时也应该销毁】这个方法的缺点就是代码比较多一点,如下:

// 声明全局的 属性 名和 属性值
TCHAR g_strKSCoreAppName[] = _T("AFX_KSInstall_CPP__12036F8B_8301_46e2_ADC5_A14A44A85877__");
HANDLE g_hValue = http://www.mamicode.com/(HANDLE)1022;

// 定义枚举窗口回调函数
BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam)
{
 //TCHAR str[200] = {0};
 //::GetWindowText(hwnd, str, 200);
 HANDLE h = GetProp(hwnd, g_strKSCoreAppName);
 if(h == g_hValue)
 {
  *(HWND*)lParam = hwnd;
  return FALSE;
 }
 return TRUE;
}

// 主窗口创建前判断
HWND oldHWnd = NULL;
::EnumWindows(EnumWndProc,(LPARAM)&oldHWnd);    //枚举所有运行的窗口
if (oldHWnd != NULL)
{
 ::MessageBox(NULL, TEXT("已经有一个实例在运行了。"), TEXT("注意"), MB_OK);

 ::ShowWindow(oldHWnd, SW_NORMAL);     // 显示
 ::SetForegroundWindow(oldHWnd);       // 激活
 return FALSE;
}

// 主窗口创建后设置,为窗口附加一个属性
::SetProp(m_hWnd, g_strKSCoreAppName, g_hValue);

// 主窗口退出时移除该附加属性
::RemoveProp(m_hWnd, g_strKSCoreAppName);

方法四

上面的方法二和方法三都有一个弊病,不知道大家发现没,那就是依赖于窗口的存在,没有窗口的程序怎么办了,用方法一是可以的,不过方法一不太适合即时修改状态,譬如我想提供选项给用户,可以即时修改是否允许多实例,像KMP就提供了即时修改是否允许多实例,使用全局变量是一个比较好的解决方案,使用全局共享变量的方法则主要是在VC框架程序中通过编译器来实现的。通过#pragma data_seg预编译指令创建一个新节,在此节中可用volatile关键字定义一个变量,而且必须对其进行初始化。Volatile关键字指定了变量可以为外部进程访问。最后,为了使该变量能够在进程互斥过程中发挥作用,还要将其设置为共享变量,同时允许具有读、写访问权限。这可以通过#pragma comment预编译指令来通知编译器。下面给出使用了全局变量的进程互斥代码清单:

#pragma data_seg("Shared") 
int volatile g_lAppInstance = 0; 
#pragma data_seg() 
#pragma comment(linker,"/section:Shared,RWS")

if (0 == g_lAppInstance)
{
 g_lAppInstance = 1;
}
else if (1 == g_lAppInstance)
{
 ::MessageBox(NULL, TEXT("已经有一个实例在运行了。"), TEXT("注意"), MB_OK);
 return FALSE;
}
else
{
 // 直接启动
}

10 如何main()函数之前执行函数

11 

C++面试题(三)