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> >)" ([email protected]@@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@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> >)" ([email protected][email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@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里面,完美运行)
================================== 访问权限冲突 ====================================
以下,我会尝试用我的理解来解释一些东西,如有错误,请大佬们指出,我会及时修正
首先,我们来看一段代码
///////// 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
---------------------------------------------------------------- 后续当咸鱼的时候在加把 ---------------------------------------------------------------------