我见过一些related posts,但我无法理解我需要做些什么来修复我为入门级C ++课程制作的程序。
我的错误是:
Build Final Project of project Final Project with configuration Debug
Ld "build/Debug/Final Project" normal x86_64
cd "/Users/nick/Dropbox/|Syncs/Xcode/Final Project"
setenv MACOSX_DEPLOYMENT_TARGET 10.6
/Developer/usr/bin/g++-4.2 -arch x86_64 -isysroot /Developer/SDKs/MacOSX10.6.sdk "- L/Users/nick/Dropbox/|Syncs/Xcode/Final Project/build/Debug" "-F/Users/nick/Dropbox/|Syncs/Xcode/Final Project/build/Debug" -filelist "/Users/nick/Dropbox/|Syncs/Xcode/Final Project/build/Final Project.build/Debug/Final Project.build/Objects-normal/x86_64/Final Project.LinkFileList" -mmacosx-version-min=10.6 -o "/Users/nick/Dropbox/|Syncs/Xcode/Final Project/build/Debug/Final Project"
Undefined symbols:
"Vector<double>::Vector()", referenced from:
_main in main.o
"Vector<double>::length()", referenced from:
_main in main.o
"Vector<double>::Vector(double const&, double const&, double const&)", referenced from:
_main in main.o
_main in main.o
"Vector<double>::getx() const", referenced from:
_main in main.o
_main in main.o
"Vector<double>::gety() const", referenced from:
_main in main.o
_main in main.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
这就是我所拥有的:
//main.cpp
#include <iostream>
#include "Vector.h"
int main () {
Vector<double> a(1, 2, 3);
Vector<double> b(2, 4, 4);
Vector<double> c;
std::cout << "Length: " << b.length() << std::endl;
std::cout << b.getx() << " ," << b.gety() << std::endl;
std::cout << c.getx() << " , " << c.gety() << std::endl;
return 0;
}
和
//Vector.h
template <class T>
class Vector {
T x, y, z;
public:
//constructors
Vector();
Vector(const T& x, const T& y, const T& z);
Vector(const Vector& u);
//accessors
T getx() const;
T gety() const;
T getz() const;
//mutators
void setx(const T& x);
void sety(const T& y);
void setz(const T& z);
//operations
void operator-();
Vector plus(const Vector& v);
Vector minus(const Vector& v);
Vector cross(const Vector& v);
T dot(const Vector& v);
void times(const T& s);
T length();
};
和Vector.cpp(虽然我修剪了一些有点重复的代码 - 例如y和z的访问器和扩展器)
//Vector.cpp
#include "Vector.h"
#include <iostream>
#include <math.h>
template class Vector<int>;
template class Vector<double>;
//default constructor
template <class T>
Vector<T>::Vector(): x(0), y(0), z(0) {}
//constructor
template <class T>
Vector<T>::Vector(const T& x, const T& y, const T& z)
{
setx(x);
sety(y);
setz(z);
}
//copy constructor
template <class T>
Vector<T>::Vector(const Vector& u)
{
x = u.getx();
y = u.gety();
z = u.getz();
}
//x accessor
template <class T>
T Vector<T>::getx() const
{
return x;
}
//y accessor
//z accessor
//x mutator
template <class T>
void Vector<T>::setx(const T& x)
{
Vector::x = x;
}
//y mutator
//z mutator
//negated Vector
template <class T>
void Vector<T>::operator-()
{
setx(-this->getx());
sety(-this->gety());
setz(-this->getz());
}
//sum
template <class T>
Vector<T> Vector<T>::plus(const Vector& v)
{
Vector ret((getx() + v.getx()), (gety() + v.gety()), (getz() + v.getz()));
return ret;
}
//difference
template <class T>
Vector<T> Vector<T>::minus(const Vector& v)
{
Vector ret((getx() - v.getx()), (gety() - v.gety()), (getz() - v.getz()));
return ret;
}
//cross product
template <class T>
Vector<T> Vector<T>::cross(const Vector& v)
{
Vector ret;
ret.setx(gety()*v.getz() - getz()*v.gety());
ret.sety(getz()*v.getx() - getx()*v.getz());
ret.setz(getx()*v.gety() - gety()*v.getx());
return ret;
}
//dot product
template <class T>
T Vector<T>::dot(const Vector& v)
{
return (getx()*v.getx() + gety()*v.gety() + getz()*v.getz());
}
//scalar times Vector
template <class T>
void Vector<T>::times(const T& s)
{
setx(getx()*s);
sety(gety()*s);
setz(getz()*s);
}
//length of Vector
template <class T>
T Vector<T>::length()
{
return sqrt((this->dot(*this)));
}
那么,到底发生了什么?是因为我有一个单独的标题&amp; Vector的.cpp文件?如何让我的主函数识别我的Vector类的函数?
答案 0 :(得分:11)
http://www.parashift.com/c++-faq-lite/templates.html
提供详细说明[35.12]为什么我不能将模板类的定义与其声明分开并将其放在.cpp文件中?
如果您只想知道如何解决这种情况,请阅读接下来的两个常见问题解答。但为了理解事情的原因,首先要接受这些事实:
现在基于这些事实,这里有一个例子,说明为什么事情就是这样。假设您有一个模板Foo定义如下:
template<typename T>
class Foo {
public:
Foo();
void someMethod(T x);
private:
T x;
};
除了成员函数的类似定义:
template<typename T>
Foo<T>::Foo()
{
...
}
template<typename T>
void Foo<T>::someMethod(T x)
{
...
}
现在假设你在文件Bar.cpp中有一些使用Foo的代码:
// Bar.cpp
void blah_blah_blah()
{
...
Foo<int> f;
f.someMethod(5);
...
}
显然某人某处必须使用构造函数定义的“模式”和someMethod()定义,并在T实际为int时实例化那些。但是如果你把构造函数和someMethod()的定义放到文件Foo.cpp中,编译器会在编译Foo.cpp时看到模板代码,它会在编译Bar.cpp时看到Foo,但是永远不会它看到模板代码和Foo的时候。因此,通过上面的规则#2,它永远不会生成Foo :: someMethod()的代码。
给专家的说明:我显然已经做了几个简化。这是故意的,所以请不要抱怨太大声。如果您知道.cpp文件和编译单元之间的区别,类模板和模板类之间的区别,以及模板实际上不仅仅是美化宏的事实,那么请不要抱怨:这个特定的问题/答案并非一开始就是针对你的。我简化了一些事情,所以新手会“得到它”,即使这样做会冒犯一些专家。
[35.13]如何使用模板函数避免链接器错误?
告诉C ++编译器在编译模板函数的.cpp文件时要进行哪些实例化。
作为示例,请考虑头文件foo.h,其中包含以下模板函数声明:
//文件“foo.h”
template<typename T>
extern void foo();
现在假设文件foo.cpp实际定义了该模板函数:
//文件“foo.cpp”
#include <iostream>
#include "foo.h"
template<typename T>
void foo()
{
std::cout << "Here I am!\n";
}
假设文件main.cpp通过调用foo():
来使用此模板函数//文件“main.cpp”
#include "foo.h"
int main()
{
foo<int>();
...
}
如果编译并(尝试)链接这两个.cpp文件,大多数编译器都会生成链接器错误。有三种解决方案。第一种解决方案是将模板函数的定义物理移动到.h文件中,即使它不是内联函数。此解决方案可能(或可能不会)导致重大代码膨胀,这意味着您的可执行文件大小可能会急剧增加(或者,如果您的编译器足够智能,可能不会;尝试并查看)。
另一个解决方案是将模板函数的定义保留在.cpp文件中,只需添加行模板void foo();到那个文件:
//文件“foo.cpp”
#include <iostream>
#include "foo.h"
template<typename T> void foo()
{
std::cout << "Here I am!\n";
}
template void foo<int>();
如果你不能修改foo.cpp,只需创建一个新的.cpp文件,如foo-impl.cpp,如下所示:
//文件“foo-impl.cpp”
#include "foo.cpp"
template void foo<int>();
请注意,foo-impl.cpp#包含.cpp文件,而不是.h文件。
答案 1 :(得分:2)
这里最简单的解决方案是包含.cc / .cpp文件,并让这些文件包含其头文件。例如,如果我们有source.cpp
和header.h
,我们想在main.cc
文件中使用源文件,那么将#include "header.h"
添加到source.cpp
和{ {1}} #include "source.cpp"
。
不确定编译器是否会对此进行优化,但这对我有用。
答案 2 :(得分:1)
是因为我有一个单独的标题&amp; Vector的.cpp文件?
是
如何让我的main函数识别Vector类的函数?
将函数模板和类模板成员函数的定义放入头文件中。
实际上,模板的定义需要在main.cpp中可用,以便使用您使用的参数(在这种情况下为double
)实例化模板。
答案 3 :(得分:-4)
通过包含cpp而不是标头来解决问题。它的模板和模板没有cpp。创建一个标题并将其余部分存储到* .inl而不是* .cpp。在* .h结束时加入inl。 这样做会。不要#include任何内容。