关于lnk2019错误

squijy 2016-07-26 04:08:57
《深入浅出MFC》中,第三章范例程序Frame6,讲MFC动态创建的程序。
我的编译环境是VS2013,C++win32控制台程序。
在MFC.H中有结构体CRuntimeClass,其中两个函数
struct CRuntimeClass
{
...
CObject* CreateObject();
static CRuntimeClass* PASCAL Load();
};

MFC.cpp中实现如下
CObject* CRuntimeClass::CreateObject()
{
...
return NULL;
}

CRuntimeClass* PASCAL CRuntimeClass::Load()
{
...
return NULL;
}
当我调换实现的顺序,让Load()在前,如下
CRuntimeClass* PASCAL CRuntimeClass::Load()
{
...
return NULL;
}
CObject* CRuntimeClass::CreateObject()
{
...
return NULL;
}
就会出现
error LNK2019: 无法解析的外部符号 "public: class CObject * __thiscall CRuntimeClass::CreateObject(void)" (?CreateObject@CRuntimeClass@@QAEPAVCObject@@XZ),该符号在函数 _main 中被引用

我问百度,觉得最有可能的解释是“C语言和C++语言混编”
学到这里较真这个为什么,新手解答。如描述不清,我就贴全部代码
...全文
169 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
flying_music 2016-07-27
  • 打赏
  • 举报
回复
引用 9 楼 squijy 的回复:
[quote=引用 8 楼 cyfcsd 的回复:] Load函数定义时,最后面那个右括号编码方式错了,你把它删了重新输入一遍
竟然是这样的,谢谢,已解决。编码方式错了,放在末尾会编译通过啊?[/quote] 对,编码方式错了,但编译器并没有发现这个错误,而是把'}'后面的东西都忽略了,所以后面那个函数的定义就相当于没写,也就出现了那个错误,这也算是微软代码编辑工具的一个bug吧 如不清楚欢迎继续追问,如满意请及时结贴,谢谢
squijy 2016-07-27
  • 打赏
  • 举报
回复
引用 8 楼 cyfcsd 的回复:
Load函数定义时,最后面那个右括号编码方式错了,你把它删了重新输入一遍
竟然是这样的,谢谢,已解决。编码方式错了,放在末尾会编译通过啊?
flying_music 2016-07-27
  • 打赏
  • 举报
回复
Load函数定义时,最后面那个右括号编码方式错了,你把它删了重新输入一遍
squijy 2016-07-27
  • 打赏
  • 举报
回复
引用 6 楼 cyfcsd 的回复:
CMyWinApp是在哪儿定义的啊
在MY.H中,都贴出来 MY.H

#pragma once
#include <iostream>
#include "MFC.H"

class CMyWinApp : public CWinApp
{
	DECLARE_DYNCREATE(CMyWinApp)
public:
	CMyWinApp()   {
	}
	~CMyWinApp()  {
	}

	virtual BOOL InitInstance();
};

class CMyFrameWnd : public CFrameWnd
{
	DECLARE_DYNCREATE(CMyFrameWnd)
public:
	CMyFrameWnd();
	~CMyFrameWnd()  {
	}
};



class CMyDoc : public CDocument
{
	DECLARE_DYNCREATE(CMyDoc)
public:
	CMyDoc()  {
	}
	~CMyDoc() {
	}
	void SayHello(){ cout << "Hello CMyDoc\n"; }
};

class CMyView : public CView
{
	DECLARE_DYNCREATE(CMyView)
public:
	CMyView()   {
	}
	~CMyView()  {
	}
	void SayHello(){ cout << "Hello CMyView\n"; }
};

// global function
void PrintAllClasses();
MY.CPP

#include"stdafx.h"
#include "MY.H"


CMyWinApp theApp;


BOOL CMyWinApp::InitInstance()
{
    m_pMainWnd = new CMyFrameWnd;
    return TRUE;
}

CMyFrameWnd::CMyFrameWnd()
{
    Create();
}

void PrintAllClasses()
{
    CRuntimeClass* pClass;

    // just walk through the simple list of registered classes
    for (pClass = CRuntimeClass::pFirstClass; pClass != NULL;
            pClass = pClass->m_pNextClass)
    {
        cout << pClass->m_lpszClassName << "\n";
        cout << pClass->m_nObjectSize << "\n";
        cout << pClass->m_wSchema << "\n";
    }
}

IMPLEMENT_DYNCREATE(CMyWinApp,CWinApp)
IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd)
IMPLEMENT_DYNCREATE(CMyView, CView)
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)
//------------------------------------------------------------------
// main
//------------------------------------------------------------------



void main()
{
  CWinApp* pApp = AfxGetApp();

  pApp->InitApplication();
  pApp->InitInstance();
  pApp->Run();

  CRuntimeClass* pClassRef;
  CObject* pOb;
  while (1)
  {
	  if ((pClassRef = CRuntimeClass::Load()) == NULL)
		  break;
	  pOb = pClassRef->CreateObject();
	  if (pOb != NULL)
		  pOb->SayHello();
  }
}
flying_music 2016-07-27
  • 打赏
  • 举报
回复
CMyWinApp是在哪儿定义的啊
squijy 2016-07-27
  • 打赏
  • 举报
回复
引用 4 楼 cyfcsd 的回复:
无法解析的外部符号,是链接时最常见的错误,其原因是一个符号只有声明,没有定义(至少编译器看不到定义),所以解决思路是找到那个符号的定义 一般只交换两个函数的定义位置应该不会有问题的,你还是看看是不是定义写错了,或者定义和声明不匹配之类的
检查好多遍定义了,真是换顺序就编译通过。贴源码吧,看能不能帮我找到错误 MFC.CPP

#include "stdafx.h"
#include "MY.H"// it should be mfc.h, but for CMyWinApp definition, so...

extern CMyWinApp theApp;

static char szCObject[] = "CObject";
CRuntimeClass CObject::classCObject =
{ szCObject, sizeof(CObject), 0xffff, NULL, NULL };
static AFX_CLASSINIT _init_CObject(&CObject::classCObject);

CRuntimeClass* CRuntimeClass::pFirstClass = NULL;



BOOL CObject::IsKindOf(const CRuntimeClass* pClass)const
{
	CRuntimeClass* pClassThis = GetRuntimeClass();
	while (pClass != NULL)
	{
		if (pClassThis == pClass)
			return TRUE;
		pClassThis = pClassThis->m_pBaseClass;
	}
	return FALSE;
}

AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
{
	pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
	CRuntimeClass::pFirstClass = pNewClass;
}

CRuntimeClass* CObject::GetRuntimeClass() const
{
	return &CObject::classCObject;
}

BOOL CWnd::Create()
{
	return TRUE;
}

BOOL CWnd::CreateEx()
{
	PreCreateWindow();
	return TRUE;
}

BOOL CWnd::PreCreateWindow()
{
	return TRUE;
}

BOOL CFrameWnd::Create()
{
	CreateEx();
	return TRUE;
}

BOOL CFrameWnd::PreCreateWindow()
{
	return TRUE;
}


IMPLEMENT_DYNAMIC(CCmdTarget, CObject)
IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp, CWinThread)
IMPLEMENT_DYNCREATE(CWnd, CCmdTarget)
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
IMPLEMENT_DYNAMIC(CDocument, CCmdTarget)
IMPLEMENT_DYNAMIC(CView, CWnd)


CWinApp* AfxGetApp()
{
	return theApp.m_pCurrentWinApp;
}

/*-----------------------------
这里是实现
-------------------------------*/
CRuntimeClass* PASCAL CRuntimeClass::Load()
{
	char szClassName[64];
	CRuntimeClass* pClass;
	cout << "enter a class name...\n";
	cin >> szClassName;

	for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
	{
		if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
			return pClass;
	}

	cout << "Error:Class not found:" << szClassName << "\n";
	return NULL;
}

CObject* CRuntimeClass::CreateObject()
{
	if (m_pfnCreateObject == NULL)
	{
		cout << "Error:Tring to create object which is not DECLARE_DYNCREATE \nor DECLARE_SERIAL:" << m_lpszClassName << "\n";
		return NULL;
	}
	CObject* pObject = NULL;
	pObject = (*m_pfnCreateObject)();
	return pObject;
}
MFC.H

#pragma once
#define BOOL int
#define TRUE 1
#define FALSE 0
#define LPCSTR  LPSTR
typedef char*   LPSTR;
#define UINT int
#define PASCAL _stdcall

#include <iostream>
using std::cout;
using std::cin;
class CObject;

/*-----------------------------
这里是定义
-------------------------------*/
struct CRuntimeClass
{
	// Attributes
	LPCSTR m_lpszClassName;
	int m_nObjectSize;
	UINT m_wSchema; // schema number of the loaded class
	CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
	CRuntimeClass* m_pBaseClass;

	CObject* CreateObject();
	static CRuntimeClass* PASCAL Load();

	// CRuntimeClass objects linked together in simple list
	static CRuntimeClass* pFirstClass; // start of class list
	CRuntimeClass* m_pNextClass;       // linked list of registered classes

};



struct AFX_CLASSINIT
{
	AFX_CLASSINIT(CRuntimeClass* pNewClass);
};

#define RUNTIME_CLASS(class_name) \
        (&class_name::class##class_name)\

#define DECLARE_DYNAMIC(class_name) \
public: \
        static CRuntimeClass class##class_name; \
        virtual CRuntimeClass* GetRuntimeClass() const;\

#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \
        static char _lpsz##class_name[] = #class_name; \
        CRuntimeClass class_name::class##class_name = { \
                _lpsz##class_name, sizeof(class_name), wSchema, pfnNew, \
                        RUNTIME_CLASS(base_class_name), NULL }; \
        static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \
        CRuntimeClass* class_name::GetRuntimeClass() const \
                { return &class_name::class##class_name; } \

#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
        _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)

#define DECLARE_DYNCREATE(class_name)\
	DECLARE_DYNAMIC(class_name)\
	static CObject* PASCAL CreateCObject();\


#define IMPLEMENT_DYNCREATE(class_name,base_class_name)\
	CObject* PASCAL class_name::CreateCObject(){return new class_name;}\
	_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,class_name::CreateCObject)\






class CObject
{
public:
	CObject::CObject()  {
	}
	CObject::~CObject() {
	}
	virtual void SayHello(){ cout << "Hello Object\n"; }
	virtual CRuntimeClass* GetRuntimeClass() const;
	BOOL IsKindOf(const CRuntimeClass* pClass)const;

public:
	static CRuntimeClass classCObject;
};

class CCmdTarget : public CObject
{
	DECLARE_DYNAMIC(CCmdTarget)
public:
	CCmdTarget()  {
	}
	~CCmdTarget() {
	}
};

class CWinThread : public CCmdTarget
{
	DECLARE_DYNAMIC(CWinThread)
public:
	CWinThread()  {
	}
	~CWinThread() {
	}

	virtual BOOL InitInstance() {
		return TRUE;
	}
	virtual int Run() {
		return 1;
	}
};

class CWnd;

class CWinApp : public CWinThread
{
	DECLARE_DYNAMIC(CWinApp)
public:
	CWinApp* m_pCurrentWinApp;
	CWnd* m_pMainWnd;

public:
	CWinApp()  {
		m_pCurrentWinApp = this;
	}
	~CWinApp() {
	}

	virtual BOOL InitApplication() {
		return TRUE;
	}
	virtual BOOL InitInstance()    {
		return TRUE;
	}
	virtual int Run() {
		return CWinThread::Run();
	}
};

class CDocument : public CCmdTarget
{
	DECLARE_DYNAMIC(CDocument)
public:
	CDocument()   {
	}
	~CDocument()  {
	}
};

class CWnd : public CCmdTarget
{
	DECLARE_DYNCREATE(CWnd)
public:
	CWnd()   {
	}
	~CWnd()  {
	}
	void SayHello(){ cout << "Hello CWnd\n"; }

	virtual BOOL Create();
	BOOL CreateEx();
	virtual BOOL PreCreateWindow();
};

class CFrameWnd : public CWnd
{
	DECLARE_DYNCREATE(CFrameWnd)
public:
	CFrameWnd()   {
	}
	~CFrameWnd()  {
	}
	BOOL Create();
	virtual BOOL PreCreateWindow();
	void SayHello(){ cout << "Hello CFrameWnd\n"; }
};

class CView : public CWnd
{
	DECLARE_DYNAMIC(CView)
public:
	CView()   {
	}
	~CView()  {
	}
};


// global function
CWinApp* AfxGetApp();

flying_music 2016-07-27
  • 打赏
  • 举报
回复
无法解析的外部符号,是链接时最常见的错误,其原因是一个符号只有声明,没有定义(至少编译器看不到定义),所以解决思路是找到那个符号的定义 一般只交换两个函数的定义位置应该不会有问题的,你还是看看是不是定义写错了,或者定义和声明不匹配之类的
squijy 2016-07-27
  • 打赏
  • 举报
回复
引用 1 楼 zhao4zhong1 的回复:
将错误信息中出现的标识符放在百度里面搜一下,看其在哪个.lib中,然后在本地硬盘上搜索该.lib,如果没有,在网上搜索相关库或模块下载安装,然后将其所在目录填写到“附加依赖库所在目录”中,将其名字添加到“附加依赖库”中,重新连接。 项目、属性、链接器、常规、附加库目录:填写附加依赖库所在目录 分号间隔多项 项目、属性、链接器、输入、附加依赖项:填写附加依赖库的名字.lib 空格或分号间隔多项
这个符号是我定义的结构中的函数,我的意思是,按照上面的顺序,程序就编译通过,换个顺序写,就编译错误,CObject* CRuntimeClass::CreateObject()实现中CObject关键字都不变蓝了,没有拼写错误。 这种情况不是缺少相应的lib吧
squijy 2016-07-27
  • 打赏
  • 举报
回复
这个符号是我定义的结构中的函数,我的意思是,按照上面的顺序,程序就编译通过,换个顺序写,就编译错误,CObject* CRuntimeClass::CreateObject()实现中CObject关键字都不变蓝了,没有拼写错误
赵4老师 2016-07-26
  • 打赏
  • 举报
回复
将错误信息中出现的标识符放在百度里面搜一下,看其在哪个.lib中,然后在本地硬盘上搜索该.lib,如果没有,在网上搜索相关库或模块下载安装,然后将其所在目录填写到“附加依赖库所在目录”中,将其名字添加到“附加依赖库”中,重新连接。 项目、属性、链接器、常规、附加库目录:填写附加依赖库所在目录 分号间隔多项 项目、属性、链接器、输入、附加依赖项:填写附加依赖库的名字.lib 空格或分号间隔多项

16,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧