C++ 踩坑记录

   这周打算当一条咸鱼,跟着菜鸟学习一下C++的一些语法,好为以后学习OpenGL做一下打算

==================================无法识别(解析)的外部命令========================================

    我遇到这个问题的时候是在写.h + .cpp的时候,这个问题最大的可能性是你在.h里面声明了一些方法,但是在.cpp里面没有相应的实现,比如

///////////////// .h  /////////////////
#pragma once
#include <iostream>

class Test
{
public:
    void Printf();
    void Printf(int i); // 注意 我没有实现这个方法  
};

/////////////////.cpp//////////////////

#include "Test.h"

void Test::Printf()
{
    std::cout<<"hello world"<<endl;
}

///////////////main.cpp///////////////
#include "test.h"

int main()
{
    Test * test = new Test();
    test->Printf("sss");
    delete test;
    system("pause"); 
}

这样,运行的时候就会出现像是这样的报错信息,而且没有行号

1>Main.obj : error LNK2001: 无法解析的外部符号 "public: void __cdecl Test::Printf(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?Printf@Test@@QEAAXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
1>C:\Users\Administrator\source\repos\C++Test\x64\Release\C++Test.exe : fatal error LNK1120: 1 个无法解析的外部命令
1>已完成生成项目“C++Test.vcxproj”的操作 - 失败。

还有一种情况,就是template<class T> 这种,在C#里面我们一般称呼他为泛型

这个报错曾经困扰了我一整天,最后还是在CSDN提问,才找到大佬的解答,错误范例如下

////// Test.h //////
#pragma once
#include "include.h"
template<class T>
class Test 
{
public:
	void Printf(T str);
};


////// Test.cpp //////
#include "test.h"

template<class T>
void Test<T>::Printf(T str)
{
	cout << str.c_str() << endl;
}

////// main.cpp //////
#include <iostream>
#include "test.h"

int main()
{
    Test<string> * test = new Test<string>();
    test->Printf("sss");
    delete test;
    system(pause);
}

//---- 报错信息 ----//

1>Main.obj : error LNK2001: 无法解析的外部符号 "public: void __cdecl Test<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::Printf(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?Printf@?$Test@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QEAAXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
1>C:\Users\Administrator\source\repos\C++Test\x64\Release\C++Test.exe : fatal error LNK1120: 1 个无法解析的外部命令
1>已完成生成项目“C++Test.vcxproj”的操作 - 失败。

刚开始的时候,我一直认为是代码问题,最后查找,并没有,于是以为是运行环境,DeBug Release X86 64都没用, 设置我还以为是DLL,最后当我把目光锁定到系统问题上时,我提问的问题得到了解答

对不起,本垃圾错了,我不该怀疑系统的,Win7,你是粑粑好吧

根据上面大佬的回答,修改代码(其实就是把.cpp Ctrl+x Ctrl+v 复制到.h里面,完美运行)

================================== 访问权限冲突 ====================================

扫描二维码关注公众号,回复: 3704971 查看本文章

以下,我会尝试用我的理解来解释一些东西,如有错误,请大佬们指出,我会及时修正

首先,我们来看一段代码

///////// Test.h 
#pragma once
#include "include.h"

class Test 
{
public:
	int t;
	Test();
	void Debug();
};

///////// Test.cpp
#include <iostream>
#include "test.h"

Test::Test() 
{
	t = 10;
}

void Test::Debug() 
{
	cout << t << endl;
}

////////// main.cpp
#include ...
int main(){
    Test* test = new Test();
    test->Debug();
    delete test;
    test->Debug(); // 注意,这里出现错误
    system("pause");
    return 0;
}

首先,我们new了一块内存,后来当我们不在使用的时候,将他的内存地址还给了管理器,但在还给管理器之后,我们又想再次使用这个地址去访问一些方法,但是这块地址现在存放的已经不再是Test类了,这块内存现在可能并没有分配出去,也就是NULL,也有可能已经分配了出去,但是却是一些其他的类型,比如Int String之类的存放,也就是说,在我们释放内存之后,再次使用这个地址访问的时候,就有无限接近100的可能是使用下面这种访问,

default->Debug();
OR
NULL->Debug();  -- 这一种应该是出现错误 0x000000发生访问冲突
OR
string->Debug();
OR 
int->Debug();

也就是说,就像是我上个月写的那个AB包加载的UnLoad() // 里面是写True 还是写False 一样,在不确定后续是否使用的时候,千万不要贸然的使用 -- Delete() OR free() OR XXX = NULL

================================== 命名空间 宏 ============================================

#ifndef -> 来自 http://www.cnblogs.com/zi-xing/p/4550246.html

首先,了解一下什么是重复加载(注意:我不确定下面这段话是否正确,只是我自己的理解

        一般来说,当我们定义了一个头文件的时候,编译器会先去查找他的说明,也就是相应的类前置说明,注,此时内存中已经有了这个类的相应说明

        而当我们无意的再次加载的时候,我们再次加载的类就会和原有的发生冲突。(我感觉这种情况就类似于我们定义了两个名称相同,返回值相同,参数相同的方法,或是类一样)而这个时候,解释器就会罢工,因为他不知道我们下一个命令是找谁的

        而假如这种编译通过的话,我们可以设想一下, 两个名称相同的类,里面有着相同的方法,定义,参数,会发生什么?我们的进程只有一条,线程也是无法脱离进程,也就是说解释器在进程中游走的时候,他会发生一种两个并行执行的True操作,但是进程只有一条啊,那么结果显而易见,就是内存瞬间爆炸,CPU烤鸡蛋

      当然,编译器不会目送着你在自己的好基友CPU原地起飞的------错误代码

----Test.h

#include "include.h"
#include <iostream>
class Test
{
public:
	int t;
	Test();
	void Debug();
};

Test::Test()
{
	t = 10;
}

void Test::Debug()
{
	cout << t << endl;
}

----main.cpp
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
int main()
{
    Test* _t = new Test();
    _t->Debug();
    system("pause");
}

--------------------------------------错误信息------------------------------------
1>c:\users\administrator\source\repos\c++test\c++test\test.h(5): error C2011: “Test”:“class”类型重定义
1>c:\users\administrator\source\repos\c++test\c++test\test.h(4): note: 参见“Test”的声明

正确写法:

----Test.h
#pragma once // 标识头文件只会被加载一次 对 就只加了这一句
#include "include.h"
#include <iostream>
class Test
{
public:
	int t;
	Test();
	void Debug();
};

Test::Test()
{
	t = 10;
}

void Test::Debug()
{
	cout << t << endl;
}

----main.cpp
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
int main()
{
    Test* _t = new Test();
    _t->Debug();
    system("pause");
}

其实,还有#ifndef 宏也可以标识头文件只被加载一次

--- ifndef 意思就是如果下面的代码块没有加载到内存中,或者说内存中还没有他(__Test__)的前置说明的话

#pragma once -- 这句话和下面的ifndef一样,都是确保头文件只会加载一次

#ifndef  __Test__ // __Test__ 是自己随意定义的

#define __Test__

#endif

---------------------------------------------------------------- 后续当咸鱼的时候在加把 ---------------------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/MikuLingSSS/article/details/83212684