在本文中,我们将不解释为什么会提示“纯虚拟函数调用”和如何提示“纯虚拟函数调用”,而是详细解释在win32平台的构造函数/析构函数中直接/间接调用纯虚拟函数时程序本身。在开始时,将显示一个经典示例,在这个示例中,它将提示一个带有“纯虚拟函数调用”的消息框。

    /**
* "pure virtual function call" on win32 platform
* filename: testWin32PVFC.cpp
*/
#include <iostream> #define PI 3.1415926
using namespace std; class Shape
{
private:
double ValuePerSquareUnit; protected:
Shape(double valuePerSquareUnit):
ValuePerSquareUnit(valuePerSquareUnit)
{
//error LNK2001: unresolved external symbol "public: virtual double __thiscall Shape::area(void)const " (?area@Shape@@UBENXZ)
//std::cout << "creating shape, area = " << area() << std::endl;
std::cout << "creating shape, value = " << value() << std::endl; //indirectly call pure virtual function in constructor
} public:
virtual double area() const = 0; double value() const
{
return ValuePerSquareUnit * area();
} virtual ~Shape()
{
printf("Shape::~Shape() is called");
} double getPerSquareUnit()
{
return ValuePerSquareUnit;
}
}; class Rectangle : public Shape
{
private:
double Width;
double Height; public:
Rectangle(double width, double height, double valuePerSquareUnit):
Shape(valuePerSquareUnit),Width(width),Height(height)
{
} virtual ~Rectangle() //can be removed
{
} virtual double area() const
{
return Width * Height;
} }; class Circle: public Shape
{
double Radius; public:
Circle(double radius, double valuePerSquareUnit):
Shape(valuePerSquareUnit),Radius(radius)
{
} virtual ~Circle() //can be removed
{
} virtual double area() const
{
return PI * Radius * Radius;
}
}; int main()
{
Rectangle* pr = new Rectangle(30, 20, 10);
Circle* pc = new Circle(15, 10); //invoke Rectangle::area()
printf("rectangle: area = %.2f, PerSquareUnit = %.2f, value = %.2f/n", pr->area(), pr->getPerSquareUnit(), pr->value());
//invoke Circle::area()
printf("circle : area = %.2f, PerSquareUnit = %.2f, value = %.2f/n", pc->area(), pc->getPerSquareUnit(), pc->value()); Shape* shape;
shape = pr;
printf("rectangle: area = %.2f, PerSquareUnit = %.2f, value = %.2f/n", shape->area(), shape->getPerSquareUnit(), shape->value()); shape = pc;
printf("circle : area = %.2f, PerSquareUnit = %.2f, value = %.2f/n", shape->area(), shape->getPerSquareUnit(), shape->value()); return 0;
}

编译执行上面的代码,报

从这个例子我们可以得出结论, 在构造函数/析构函数中,直接调用纯虚函数,会出现编译错误,如
error LNK2001: unresolved external symbol "public: virtual double __thiscall Shape::area(void)const " (?area@Shape@@UBENXZ)
间接调用纯虚函数,提示“pure virtual function call”
调试这个程序,我们可以看到下面列出的Shape::value()的反汇编代码,我的注释被嵌入了。
 double value() const

    {

004118F0  push        ebp 

004118F1  mov         ebp,esp

004118F3  sub         esp,0CCh

004118F9  push        ebx 

004118FA  push        esi 

004118FB  push        edi 

004118FC  push        ecx 

004118FD  lea         edi,[ebp-0CCh]

  mov         ecx,33h

  mov         eax,0CCCCCCCCh

0041190D  rep stos    dword ptr es:[edi]

0041190F  pop         ecx 

  mov         dword ptr [ebp-],ecx

    return ValuePerSquareUnit * area();

  mov         eax,dword ptr [this]     //eax = 0x003b5fc0, move ‘this’ pointer to eax

  mov         edx,dword ptr [eax]      //edx = 0x00417800, move vfptr to edx

  mov         esi,esp

0041191A  mov         ecx,dword ptr [this]    //ecx = 0x003b5fc0, move ‘this’ pointer to ecx

0041191D  mov         eax,dword ptr [edx]     //eax = 0x004111f4, the address of __purecall, move the first virtual function address to eax

0041191F  call        eax                     //call this virtual function

  cmp         esi,esp

  call        @ILT+(__RTC_CheckEsp) (4111F9h)

  mov         ecx,dword ptr [this]

0041192B  fmul        qword ptr [ecx+]

    }

0041192E  pop         edi 

0041192F  pop         esi 

  pop         ebx 

  add         esp,0CCh

  cmp         ebp,esp

  call        @ILT+(__RTC_CheckEsp) (4111F9h)

0041193E  mov         esp,ebp

  pop         ebp 

  ret    

可以从下图中验证反汇编代码和我的注释,下图是从调试中捕获的。

 

要找到0x004111f4的地址,需要在反汇编代码中找到该程序的跳转表。然后,我们发现它列在下面,其中列出了所有跳转项。

00411005  jmp         _setdefaultprecision (413E80h)

0041100A  jmp         _setargv (413F20h)

0041100F  jmp         std::ios_base::good (41283Ah)

00411014  jmp         DebugBreak (414B78h)

00411019  jmp         _RTC_GetErrDesc (413BE0h)

0041101E  jmp         Rectangle::area (411BD0h)

00411023  jmp         __p__fmode (413F94h)

00411028  jmp         __security_check_cookie (412870h)

0041102D  jmp         IsDebuggerPresent (414B6Ch)

00411032  jmp         std::basic_ostream<char,std::char_traits<char> >::sentry::operator bool (412630h)

00411037  jmp         type_info::operator= (412BA0h)

0041103C  jmp         _RTC_Terminate (413F60h)

00411041  jmp         WideCharToMultiByte (414B7Eh)

00411046  jmp         _RTC_AllocaHelper (412940h)

0041104B  jmp         _RTC_GetErrorFuncW (413CA0h)

00411050  jmp         _RTC_NumErrors (413BD0h)

00411055  jmp         std::basic_ios<char,std::char_traits<char> >::rdbuf (412810h)

0041105A  jmp         __setusermatherr (413F04h)

0041105F  jmp         Sleep (414B48h)

00411064  jmp         type_info::_type_info_dtor_internal_method (414B12h)

00411069  jmp         Circle::`scalar deleting destructor' (411DC0h)

0041106E  jmp         Rectangle::Rectangle (4119A0h)

00411073  jmp         std::basic_ios<char,std::char_traits<char> >::setstate (4127ECh)

00411078  jmp         GetModuleFileNameW (414BD2h)

0041107D  jmp         __security_init_cookie (414120h)

00411082  jmp         Shape::getPerSquareUnit (411960h)

00411087  jmp         Circle::`scalar deleting destructor' (411DC0h)

0041108C  jmp         SetUnhandledExceptionFilter (414B66h)

00411091  jmp         _cexit (41428Ch)

00411096  jmp         Shape::`scalar deleting destructor' (411AF0h)

0041109B  jmp         _CrtDbgReportW (414504h)

004110A0  jmp         VirtualQuery (414BD8h)

004110A5  jmp         atexit (4140E0h)

004110AA  jmp         MultiByteToWideChar (414B84h)

004110AF  jmp         FatalAppExitA (414BBAh)

004110B4  jmp         std::endl (4127E6h)

004110B9  jmp         _RTC_SetErrorType (413C00h)

004110BE  jmp         _except_handler4 (414520h)

004110C3  jmp         _lock (414B30h)

004110C8  jmp         std::basic_streambuf<char,std::char_traits<char> >::_Unlock (412852h)

004110CD  jmp         GetProcAddress (414B90h)

004110D2  jmp         std::char_traits<char>::length (412828h)

004110D7  jmp         _RTC_CheckStackVars (4128C0h)

004110DC  jmp         operator delete (412858h)

004110E1  jmp         std::char_traits<char>::eq_int_type (4127FEh)

004110E6  jmp         type_info::_type_info_dtor_internal_method (414B12h)

004110EB  jmp         std::uncaught_exception (412846h)

004110F0  jmp         __report_gsfailure (4130E0h)

004110F5  jmp         terminate (414B0Ch)

004110FA  jmp         _exit (414280h)

004110FF  jmp         GetCurrentThreadId (414BA8h)

00411104  jmp         _initterm (41450Ah)

00411109  jmp         std::basic_ios<char,std::char_traits<char> >::tie (412834h)

0041110E  jmp         std::ios_base::width (4127F2h)

00411113  jmp         GetCurrentProcess (414B5Ah)

00411118  jmp         Circle::~Circle (411E30h)

0041111D  jmp         std::basic_streambuf<char,std::char_traits<char> >::sputc (41280Ah)

00411122  jmp         std::basic_ostream<char,std::char_traits<char> >::operator<< (4127E0h)

00411127  jmp         _encode_pointer (414100h)

0041112C  jmp         std::ios_base::width (412822h)

00411131  jmp         _RTC_UninitUse (413A80h)

00411136  jmp         _RTC_Shutdown (412AD0h)

0041113B  jmp         type_info::`vector deleting destructor' (412B10h)

00411140  jmp         _FindPESection (414320h)

00411145  jmp         Rectangle::`scalar deleting destructor' (411C20h)

0041114A  jmp         _configthreadlocale (413E78h)

0041114F  jmp         _RTC_InitBase (412A90h)

00411154  jmp         _RTC_StackFailure (413700h)

00411159  jmp         LoadLibraryA (414B96h)

0041115E  jmp         RaiseException (414B72h)

00411163  jmp         _crt_debugger_hook (414550h)

00411168  jmp         _ValidateImageBase (4142A0h)

0041116D  jmp         Shape::value (4118F0h)

00411172  jmp         InterlockedCompareExchange (414B4Eh)

00411177  jmp         Rectangle::~Rectangle (411C90h)

0041117C  jmp         Shape::Shape (411A30h)

00411181  jmp         std::basic_streambuf<char,std::char_traits<char> >::_Lock (41284Ch)

00411186  jmp         std::char_traits<char>::eof (412804h)

0041118B  jmp         std::basic_ostream<char,std::char_traits<char> >::sentry::~sentry (412560h)

00411190  jmp         Shape::~Shape (411B60h)

00411195  jmp         GetProcessHeap (414BCCh)

0041119A  jmp         _RTC_SetErrorFuncW (413C60h)

0041119F  jmp         _onexit (413FA0h)

004111A4  jmp         NtCurrentTeb (412FF0h)

004111A9  jmp         HeapFree (414BC0h)

004111AE  jmp         std::operator<<<std::char_traits<char> > (411E90h)

004111B3  jmp         _RTC_SetErrorFunc (413C30h)

004111B8  jmp         _invoke_watson_if_error (413ED0h)

004111BD  jmp         std::basic_ostream<char,std::char_traits<char> >::operator<< (4127DAh)

004111C2  jmp         std::basic_ostream<char,std::char_traits<char> >::_Sentry_base::~_Sentry_base (412730h)

004111C7  jmp         TerminateProcess (414B54h)

004111CC  jmp         std::basic_ostream<char,std::char_traits<char> >::flush (41282Eh)

004111D1  jmp         mainCRTStartup (412CF0h)

004111D6  jmp         QueryPerformanceCounter (414B9Ch)

004111DB  jmp         __p__commode (413F8Eh)

004111E0  jmp         _unlock (414B24h)

004111E5  jmp         GetCurrentProcessId (414BAEh)

004111EA  jmp         _RTC_CheckStackVars2 (412980h)

004111EF  jmp         __set_app_type (414106h)

004111F4  jmp         _purecall (412BB4h)

004111F9  jmp         _RTC_CheckEsp (412890h)

004111FE  jmp         main (4115B0h)

00411203  jmp         Rectangle::`scalar deleting destructor' (411C20h)

00411208  jmp         _RTC_Initialize (413F30h)

0041120D  jmp         _controlfp_s (414B18h)

00411212  jmp         GetSystemTimeAsFileTime (414BB4h)

00411217  jmp         _decode_pointer (414B36h)

0041121C  jmp         _invoke_watson (414B1Eh)

00411221  jmp         _RTC_GetSrcLine (414560h)

00411226  jmp         _CRT_RTC_INITW (413CA6h)

0041122B  jmp         GetTickCount (414BA2h)

00411230  jmp         std::basic_streambuf<char,std::char_traits<char> >::sputn (4127F8h)

00411235  jmp         _IsNonwritableInCurrentImage (4143B0h)

0041123A  jmp         __CxxFrameHandler3 (41286Ah)

0041123F  jmp         HeapAlloc (414BC6h)

00411244  jmp         _amsg_exit (41410Ch)

00411249  jmp         operator new (412864h)

0041124E  jmp         _XcptFilter (414286h)

00411253  jmp         _CrtSetCheckCount (414298h)

00411258  jmp         InterlockedExchange (414B42h)

0041125D  jmp         UnhandledExceptionFilter (414B60h)

00411262  jmp         std::basic_ostream<char,std::char_traits<char> >::sentry::sentry (412400h)

00411267  jmp         type_info::type_info (412AF0h)

0041126C  jmp         printf (41285Eh)

00411271  jmp         Circle::Circle (411CF0h)

00411276  jmp         _except_handler4_common (414B3Ch)

0041127B  jmp         _matherr (413F10h)

00411280  jmp         std::basic_ios<char,std::char_traits<char> >::fill (412816h)

00411285  jmp         __getmainargs (414112h)

0041128A  jmp         __ArrayUnwind (413D90h)

0041128F  jmp         Circle::area (411D70h)

00411294  jmp         lstrlenA (414B8Ah)

00411299  jmp         _RTC_Failure (413300h)

0041129E  jmp         std::ios_base::flags (41281Ch)

004112A3  jmp         _RTC_AllocaFailure (413870h)

004112A8  jmp         Shape::`scalar deleting destructor' (411AF0h)

004112AD  jmp         DebuggerKnownHandle (413230h)

004112B2  jmp         exit (414292h)

004112B7  jmp         std::basic_ostream<char,std::char_traits<char> >::_Sentry_base::_Sentry_base (412670h)

004112BC  jmp         __dllonexit (414B2Ah)

004112C1  jmp         FreeLibrary (414BDEh)

004112C6  jmp         `eh vector destructor iterator' (413CB0h)

004112CB  jmp         _initterm_e (414510h)

004112D0  jmp         std::basic_ostream<char,std::char_traits<char> >::_Osfx (412840h)

004112D5  jmp         _RTC_GetErrorFunc (413C90h)

它表示程序跳转到地址0x412BB4,下面列出的0x00412BB4中的代码,其中,我们可以看到它是间接寻址。它将跳转到0x0041B418的内容。

_purecall:

00412BB4  jmp         dword ptr [__imp___purecall (41B418h)]

从下图可以看出,0x0041B418的内容是0x102527f0,这是purecall的起始地址。

我们继续执行步骤,然后,它将跳到0x102527f0,即purecall的起始地址。从下图中,我们可以清楚地看到它。

purecall的反汇编代码如下

void __cdecl _purecall(

        void

        )

{

102527F0  push        ebp 

102527F1  mov         ebp,esp

102527F3  push        ecx 

    _purecall_handler purecall = (_purecall_handler) _decode_pointer(__pPurecall);
02527F4 mov eax,dword ptr [___pPurecall (10313144h)] 102527F9 push eax 102527FA call _decode_pointer (10204900h) 102527FF add esp, mov dword ptr [purecall],eax if(purecall != NULL) cmp dword ptr [purecall], je _purecall+1Eh (1025280Eh) { purecall();
025280B call dword ptr [purecall] /* shouldn't return, but if it does, we drop back to default behaviour */ } _NMSG_WRITE(_RT_PUREVIRT); 1025280E push 19h 10252810 call _NMSG_WRITE (10202AA0h) 10252815 add esp,4 /* do not write the abort message */ _set_abort_behavior(0, _WRITE_ABORT_MSG); 10252818 push 1 1025281A push 1025281C call _set_abort_behavior (10218780h) 10252821 add esp,8 abort(); 10252824 call abort (10218640h) } 10252829 mov esp,ebp 1025282B pop ebp 1025282C ret

源代码如下:D:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\purevirt.c

    /////////////////////////////////////////////////////////////////////////////
//
// The global variable:
// extern _purecall_handler __pPurecall; /***
*void _purecall(void) -
*
*Purpose:
* The compiler calls this if a pure virtual happens
*
*Entry:
* No arguments
*
*Exit:
* Never returns
*
*Exceptions:
*
*******************************************************************************/ void __cdecl _purecall(
void
)
{
_purecall_handler purecall = (_purecall_handler) _decode_pointer(__pPurecall);
if(purecall != NULL)
{
purecall(); /* shouldn't return, but if it does, we drop back to
default behaviour
*/
} _NMSG_WRITE(_RT_PUREVIRT);
/* do not write the abort message */
_set_abort_behavior(, _WRITE_ABORT_MSG);
abort();
}

弹出提示框的消息来源如下

_RT_PUREVIRT 宏

//file: src/rterr.h

#define _RT_PUREVIRT   25    /* pure virtual function call attempted (C++ error) */

_RT_PUREVIRT_TXT 宏

//file: src/cmsgs.h

#define EOL "/r/n"

#define _RT_PUREVIRT_TXT   "R6025" EOL "- pure virtual function call" EOL
消息列表
//file: src/crt0msg.c
* struct used to lookup and access runtime error messages */ struct rterrmsgs { int rterrno; /* error number */ char *rterrtxt; /* text of error message */ }; /* runtime error messages */ static struct rterrmsgs rterrs[] = { /* 2 */ { _RT_FLOAT, _RT_FLOAT_TXT }, /* 8 */ { _RT_SPACEARG, _RT_SPACEARG_TXT }, /* 9 */ { _RT_SPACEENV, _RT_SPACEENV_TXT }, /* 10 */ { _RT_ABORT, _RT_ABORT_TXT }, /* 16 */ { _RT_THREAD, _RT_THREAD_TXT }, /* 17 */ { _RT_LOCK, _RT_LOCK_TXT }, /* 18 */ { _RT_HEAP, _RT_HEAP_TXT }, /* 19 */ { _RT_OPENCON, _RT_OPENCON_TXT }, /* 22 */ /* { _RT_NONCONT, _RT_NONCONT_TXT }, */ /* 23 */ /* { _RT_INVALDISP, _RT_INVALDISP_TXT }, */ /* 24 */ { _RT_ONEXIT, _RT_ONEXIT_TXT }, /* 25 */ { _RT_PUREVIRT, _RT_PUREVIRT_TXT }, /* 26 */ { _RT_STDIOINIT, _RT_STDIOINIT_TXT }, /* 27 */ { _RT_LOWIOINIT, _RT_LOWIOINIT_TXT }, /* 28 */ { _RT_HEAPINIT, _RT_HEAPINIT_TXT }, ///* 29 */ //{ _RT_BADCLRVERSION, _RT_BADCLRVERSION_TXT }, /* 30 */ { _RT_CRT_NOTINIT, _RT_CRT_NOTINIT_TXT }, /* 31 */ { _RT_CRT_INIT_CONFLICT, _RT_CRT_INIT_CONFLICT_TXT}, /* 32 */ { _RT_LOCALE, _RT_LOCALE_TXT}, /* 33 */ { _RT_CRT_INIT_MANAGED_CONFLICT, _RT_CRT_INIT_MANAGED_CONFLICT_TXT}, /* 34 */ { _RT_CHECKMANIFEST, _RT_CHECKMANIFEST_TXT}, ///* 35 - not for _NMSG_WRITE, text passed directly to FatalAppExit */ //{ _RT_COOKIE_INIT, _RT_COOKIE_INIT_TXT}, /* 120 */ { _RT_DOMAIN, _RT_DOMAIN_TXT }, /* 121 */ { _RT_SING, _RT_SING_TXT }, /* 122 */ { _RT_TLOSS, _RT_TLOSS_TXT }, /* 252 */ { _RT_CRNL, _RT_CRNL_TXT }, /* 255 */ { _RT_BANNER, _RT_BANNER_TXT } }; /* number of elements in rterrs[] */ #define _RTERRCNT ( sizeof(rterrs) / sizeof(struct rterrmsgs) )

这可以从以下从调试中捕获的图中进行验证。

哪个函数提示消息?

//file: src/crt0msg.c

/***

*__NMSG_WRITE(message) - write a given message to handle 2 (stderr)

*

*Purpose:

*       This routine writes the message associated with rterrnum

*       to stderr.

*

*Entry:

*       int rterrnum - runtime error number

*

*Exit:

*       no return value

*

*Exceptions:

*       none

*

*******************************************************************************/

void __cdecl _NMSG_WRITE (

        int rterrnum

        )

{

        int tblindx;

        DWORD bytes_written;            /* bytes written */

        for ( tblindx =  ; tblindx < _RTERRCNT ; tblindx++ )

            if ( rterrnum == rterrs[tblindx].rterrno )    //in rterrs array, find the mapped message

                break;

        if ( tblindx < _RTERRCNT )

        {

#ifdef _DEBUG

            /*

             * Report error.

             *

             * If _CRT_ERROR has _CRTDBG_REPORT_WNDW on, and user chooses

             * "Retry", call the debugger.

             *

             * Otherwise, continue execution.

             *

             */

            if (rterrnum != _RT_CRNL && rterrnum != _RT_BANNER && rterrnum != _RT_CRT_NOTINIT)

            {

                if ( == _CrtDbgReport(_CRT_ERROR, NULL, , NULL, rterrs[tblindx].rterrtxt))

                    _CrtDbgBreak();

            }

#endif  /* _DEBUG */

            if ( (_set_error_mode(_REPORT_ERRMODE) == _OUT_TO_STDERR) ||

                 ((_set_error_mode(_REPORT_ERRMODE) == _OUT_TO_DEFAULT) &&

                  (__app_type == _CONSOLE_APP)) )

            {

                HANDLE hStdErr = GetStdHandle(STD_ERROR_HANDLE);

                if (hStdErr && hStdErr!=INVALID_HANDLE_VALUE)

                {

                    WriteFile( hStdErr,

                                  rterrs[tblindx].rterrtxt,

                                  (unsigned long)strlen(rterrs[tblindx].rterrtxt),

                                  &bytes_written,

                                  NULL );

                }

            }

            else if (rterrnum != _RT_CRNL)

            {

                #define MSGTEXTPREFIX "Runtime Error!/n/nProgram: "

                static char outmsg[sizeof(MSGTEXTPREFIX) + _MAX_PATH +  + ];

                    // runtime error msg + progname + 2 newline + runtime error text.

                char * progname = &outmsg[sizeof(MSGTEXTPREFIX)-];

                size_t progname_size = _countof(outmsg) - (progname - outmsg);

                char * pch = progname;

                _ERRCHECK(strcpy_s(outmsg, _countof(outmsg), MSGTEXTPREFIX));

                progname[MAX_PATH] = '/0';

                if (!GetModuleFileName(NULL, progname, MAX_PATH))

                    _ERRCHECK(strcpy_s(progname, progname_size, "<program name unknown>"));

                #define MAXLINELEN 60

                if (strlen(pch) +  > MAXLINELEN)

                {

                    pch += strlen(progname) +  - MAXLINELEN;

                    _ERRCHECK(strncpy_s(pch, progname_size - (pch - progname), "...", ));

                }

                _ERRCHECK(strcat_s(outmsg, _countof(outmsg), "/n/n"));

                _ERRCHECK(strcat_s(outmsg, _countof(outmsg), rterrs[tblindx].rterrtxt));

                __crtMessageBoxA(outmsg,

                        "Microsoft Visual C++ Runtime Library",

                        MB_OK|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);

            }

        }

}

整个调用栈如下:

当纯虚函数显式实现时是什么情况?

在类内实现它

class Shape

{

...

public:

    virtual double area() const = 

    {

        std::cout << "pure virtual area() called" << std::endl;

        return ;

}

...

};

没有编译器错误,但会提示“pure virtual function call”

本文通过一个典型的例子,详细说明了在win32平台的构造函数/析构函数中直接/间接调用纯虚函数时的程序本身。列出了一些msvc-crt源代码,分析了purecall函数及其反汇编代码。此外,我们还介绍了该程序的跳转表,以及提示消息的来源,该跳转表是在数组(rterrs)和一些宏中定义的,例如_RT_PUREVIRT和_RT_PUREVIRT_TXT。最后,我们给出了纯虚函数的两个实现来验证它是否工作,从结果中我们发现,即使有纯虚函数的实现,编译器也会显式忽略实现的代码,仍然会调用pure call,并提示“pure virtual function call”。

 
 

深入解析pure virtual function call的更多相关文章

  1. pure virtual function call

    2015-04-08 10:58:19 基类中定义了纯虚函数,派生类中将其实现. 如果在基类的构造函数或者析构函数中调用了改纯虚函数, 则会出现R6205 Error: pure virtual fu ...

  2. Mindjet MindManager 2012 从模板创建出现“Runtime Error pure virtual function call” 解决方法

    我的Mindjet MindManager 2012 Pro也就是MindManager10 在应用模板之后总会显示 Microsoft Visual C++ Runtime Library Runt ...

  3. why pure virtual function has definition 为什么可以在基类中实现纯虚函数

    看了会音频,无意搜到一个frameworks/base/include/utils/Flattenable.h : virtual ~Flattenable() = 0; 所以查了下“纯虚函数定义实现 ...

  4. [C++] Pure Virtual Function and Abstract Class

    Pure Virtual Function Abstract Class

  5. 纯虚函数(pure virtual function )和抽象类(abstract base class)

    函数体=0的虚函数称为“纯虚函数”.包含纯虚函数的类称为“抽象类” #include <string> class Animal // This Animal is an abstract ...

  6. 结合实例详解"pure Virtual function called"

    作者:阿波 链接:http://blog.csdn.net/livelylittlefish/article/details/9750593 (4年前的一篇文章,翻出来共享一下.) 本实例即为经典的讲 ...

  7. c++ virtual 和 pure virtual的区别

    参考资料: http://stackoverflow.com/questions/1306778/c-virtual-pure-virtual-explained 验证代码: #include < ...

  8. OD: Windows Security Techniques & GS Bypassing via C++ Virtual Function

    Windows 安全机制 漏洞的万源之本在于冯诺依曼设计的计算机模型没有将代码和数据进行区分——病毒.加壳脱壳.shellcode.跨站脚本攻击.SQL注入等都是因为计算机把数据和代码混淆这一天然缺陷 ...

  9. (转) Virtual function

    原文地址:http://en.wikipedia.org/wiki/Virtual_function In object-oriented programming, a virtual functio ...

随机推荐

  1. Go基础编程实践(二)—— 类型转换

    bool to string strconv包的FormatBool函数用于将bool转为string package main import ( "fmt" "strc ...

  2. cocos creator ScrollView组件scrollToOffset()方法的使用

    前言 之前想用scrollToOffset()在打开界面时,滑动窗口滑动到一个相对应的位置,但是使用scrollToOffset()这个方法的时候,没起作用.然后就用了其他方法来实现相同的效果.现在有 ...

  3. 已拦截跨源请求:同源策略禁止读取位于XXX的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin'

    vue+springboot项目 前端发送请求微信 URL:http:/.........(企业微信的路径) 请求成功,数据发送过去可以接收到,处理完毕后发送返回值给我 我这边前端网络响应处可以看到返 ...

  4. 环境变量-path

    配置的是bin二进制可执行程序,用于系统查找程序的位置

  5. 2019 网宿科技java面试笔试题 (含面试题解析)

    本人3年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.网宿科技等公司offer,岗位是Java后端开发,最终选择去了网宿科技. 面试了很多家公司,感觉大部分公司考察的点 ...

  6. Android App 架构演变

    文:https://www.jianshu.com/p/ce26e7960926 最近App项目(MVC架构)越做越大,协同开发效率较低,维护困难,所以产生了调整架构的想法,在 简书.csdn.知乎上 ...

  7. Java 单文件、多文件上传 / 实现上传进度条

    博客地址:https://ainyi.com/76 日常,工作 在这里总结一下上传吧(是以前做过的练习,就汇总到个人博客吧) java ssm 框架实现文件上传 实现:单文件上传.多文件上传(单选和多 ...

  8. PHP 将json的int类型转换为string类型 解决php bigint转科学计数法的问题

    /** * 将json的int类型转换为string类型 * @param $str * @param int $minLength 最小的转换位数,即只有大于等于这个长度的数字才会被转换为字符串 * ...

  9. SpringBoot2.x服务器端主动推送技术

    一.服务端推送常用技术介绍 服务端主流推送技术:websocket.SSE等 1.客户端轮询:ajax定时拉取后台数据 js   setInterval定时函数  +  ajax异步加载  定时向服务 ...

  10. MSSQL镜像场景

    1.版本:一般MSSQL2016以下版本使用. 2.适用小数据库容量的异地备份:如果是数据库容量较大,产生的日志比较多:经测试,9G的数据库大小,镜像数月个日志大小达到400G,硬盘开销太大.