C++ OOP LNK2001 错误
C++ OOP LNK2001 ERROR
如标题所示,我在 C++ 中遇到了一个 OOP 错误,LNK2001 未解决的外部错误。这是我的代码,我哪里出错了?
我正在使用sfml来使用VS2015中的图形。
// OOPExample.hpp
#pragma once
#include <SFML\Graphics.hpp>
#include <SFML\System.hpp>
#ifndef OOPEX_H
#define OOPEX_H
class OOPExample{
public:
static sf::CircleShape shape;
static float rot;
static void draw();
static void rotate();
};
#endif // OOPEX_H
// OOPExample.cpp
#include "OOPExample.hpp"
#include <SFML\Graphics.hpp>
void OOPExample::rotate() {
OOPExample::rot += 0.1f;
return;
};
void OOPExample::draw() {
OOPExample::shape.setFillColor(sf::Color::Red);
OOPExample::shape.setRotation(rot);
return;
};
// Source.cpp
#include <SFML/Graphics.hpp>
#include "OOPExample.hpp"
int main()
{
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
OOPExample oopexample();
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(oopexample().shape);
window.display();
}
return 0;
}
据我所见,我似乎需要在 OOPExample.hpp 中声明的方法的定义,但我在 OOPExample.cpp 中有那些确切的定义。我是否在 Source.cpp 中错误地实例化了 class?
关于 link 错误的问题。评论突出显示了其中的大部分...这些不是 OOP 错误,而是 link 构建项目时的时间错误。不知道大家有没有编译system-level语言的经验;但学习 compile-link 循环的基础知识以及 link 人员在将最终程序组合在一起时的期望是个好主意。下面是一个如何定义静态成员变量的简单示例。
// class1.h
Class1
{
public:
private:
static float rotation;
};
// class1.cpp
#include "class1.h"
int Class1::rotation = 5.0f;
请注意 int Class1::rotation = 5.0f;
在程序初始化时发生一次。
我不知道您是否在遵循一些教程,他们是如何创建这个 class 的,但是您的静态成员数量令人担忧。这是一个 OOP 问题。如果你想制作许多 objects/instances 个 OOPExample,你需要了解静态的含义。在 class 的上下文中,当您将 static 关键字应用于变量时,这意味着所有 OOPExample objects 将共享该变量。这使得静态成员变量适用于默认值和给定的数字 class 之类的东西。您可以使用 static int OOPExample::count;
来计算您创建的 OOPExample objects 的数量。我稍后会把它放在一个例子中。
link 错误的原因可能有很多,尤其是缺少定义。 PcAF 在您的问题的评论中强调了一个重要的问题。但您也可能缺少 SFML 库。我依稀记得 SFML 教程,其中包括有关如何 link 在您的环境中使用它们的库的详细说明。在 VS 中,它将位于您的项目属性中的某个位置。如果你在 header 中声明了一些不在实现中的东西(通常是 cpp),你显然会得到类似的错误。您的静态变量就是这种情况,但也适用于函数。
现在你提供的三个文件有很多错误。我对它们进行了编辑以突出一些问题,但它远非完美。我不会以这种方式处理它,因为 sf::CircleShape 已经是一个 object-orientated 实体。它包含您要实现的所有内容。从来没有 over-abstract 问题(我在某个时候也意识到我们正在旋转一个实心圆哈哈)。你真的应该按照建议得到一本好的教科书,并从 ground-up 开始。 SFML 是一个巨大的库,它会分散您对 C++ 基础知识的理解。 OOP 只是 C++ 的一个方面,您需要掌握所有 C++ 基础知识才能有效地使用 OOP。如果这样做,您将拥有最强大的可用抽象机制(在我看来)。
我的编辑如下,但实际上,这只是兔子洞有多深的演示(它变得更糟)。如何实例化 OOPExample 显示在 main.
// OOPExample.h
#ifndef OOPEX_H
#define OOPEX_H
// Only include what you need to. Users of this header should be exposed to as
// little SFML as possible.
#include <SFML/Graphics/CircleShape.hpp>
class OOPExample{
public:
// Parameterless constructor.
OOPExample(); // Note, this sets the rotation to the default rotation.
// One that takes a initial rotation.
OOPExample(float initial_rotation);
// Rotate 0.1f (by default) or by user specified amount.
void rotate(float rotation = 0.1f);
// window.draw() takes a Drawable as its first argument. Fortunately,
// CircleShape is a shape which in turn is a Drawable. Notice that we
// return by constant reference. Callers cannot edit our shape but they
// get a reference to the sf::CircleShape shape instance so they can read
// it.
// const, & (i.e. reference), pointers requires a deep understanding of
// object ownership, copying by value, by reference, and now of
// particular interest in C++11, moving.
const sf::CircleShape &getShape() const;
// You forgot to declare and define this.
void setRotation(float rotation);
// Set the default rotation for all objects created with the
// parameterless constructor.
static void setDefaultRotation(float rotation);
// The destructor.
virtual ~OOPExample();
private:
sf::CircleShape shape;
// sf::CircleShape already has a rotation with getters and setters.
// Don't over abstract!
// Our setRotation, rotate functions seem a bit unneccesary.
// float rotation;
// Defaults.
static sf::CircleShape default_circle;
static float default_rotation;
// Count example.
static int count;
};
#endif // OOPEX_H
// OOPExample.cpp
// Personally, and I know with most other C++ developers, I prefer my header's
// extension to be .h. .hpp usually identifies headers with
// implementations/definitions of classes in the header file itself (necessary
// in some circumstances).
#include "OOPExample.h"
//
// How to initialise static member variables. This happens once at the
// beginning of the program.
//
// All our circles have a default radius of 5.
sf::CircleShape OOPExample::default_circle = sf::CircleShape(5);
// And rotation of 0.
float OOPExample::default_rotation = 0;
int OOPExample::count = 0;
// The definition of the parameterless constructor.
OOPExample::OOPExample()
// A class initialiser list. How we build a new object.
: shape(default_circle) // We copy the default circle.
{
// Do other stuff to construct the object if you need to. For example:
shape.setFillColor(sf::Color::Red);
setRotation(default_rotation);
count++; // We just made another OOPEXample instance.
}
// The definition of a constructor that takes an initial rotation. I just
// realised we are rotating a circle!
OOPExample::OOPExample(float initial_rotation)
: shape(default_circle) // We copy the default circle.
{
// Do other stuff to construct the object if you need to. For example:
shape.setFillColor(sf::Color::Red);
// Notice: we used the user provided argument this time.
setRotation(initial_rotation);
count++; // We just made another OOPEXample instance.
}
void OOPExample::rotate(float rotation)
{
shape.rotate(rotation);
// return; // No need to specify a return for a void.
}
const sf::CircleShape &OOPExample::getShape() const
{
return shape;
}
void OOPExample::setRotation(float rotation)
{
shape.setRotation(rotation);
}
void OOPExample::setDefaultRotation(float rotation)
{
// OOPExample scoping is unnecessary.
OOPExample::default_rotation = rotation;
}
OOPExample::~OOPExample()
{
// Do things required for cleanup, i.e. deinit.
// One OOPExample just reached the end of its lifetime. Either it
// was deleted or reached the end of the
// scope (i.e. {}) it was created in.
count--;
}
// main.cpp
#include "OOPExample.h"
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
// Call the default, parameterless, constructor to instantiate an object
// of OOPExample.
OOPExample oopexample;
// Create another with a initial rotation of your choosing.
OOPExample another_obj(0.5f);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
// The instance object of OOPexample is referred to by oopexample.
// window.draw(oopexample().shape);
// This member is now private.
//window.draw(oopexample.shape);
window.draw(oopexample.getShape());
window.display();
}
return 0;
}
如标题所示,我在 C++ 中遇到了一个 OOP 错误,LNK2001 未解决的外部错误。这是我的代码,我哪里出错了? 我正在使用sfml来使用VS2015中的图形。
// OOPExample.hpp
#pragma once
#include <SFML\Graphics.hpp>
#include <SFML\System.hpp>
#ifndef OOPEX_H
#define OOPEX_H
class OOPExample{
public:
static sf::CircleShape shape;
static float rot;
static void draw();
static void rotate();
};
#endif // OOPEX_H
// OOPExample.cpp
#include "OOPExample.hpp"
#include <SFML\Graphics.hpp>
void OOPExample::rotate() {
OOPExample::rot += 0.1f;
return;
};
void OOPExample::draw() {
OOPExample::shape.setFillColor(sf::Color::Red);
OOPExample::shape.setRotation(rot);
return;
};
// Source.cpp
#include <SFML/Graphics.hpp>
#include "OOPExample.hpp"
int main()
{
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
OOPExample oopexample();
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(oopexample().shape);
window.display();
}
return 0;
}
据我所见,我似乎需要在 OOPExample.hpp 中声明的方法的定义,但我在 OOPExample.cpp 中有那些确切的定义。我是否在 Source.cpp 中错误地实例化了 class?
关于 link 错误的问题。评论突出显示了其中的大部分...这些不是 OOP 错误,而是 link 构建项目时的时间错误。不知道大家有没有编译system-level语言的经验;但学习 compile-link 循环的基础知识以及 link 人员在将最终程序组合在一起时的期望是个好主意。下面是一个如何定义静态成员变量的简单示例。
// class1.h
Class1
{
public:
private:
static float rotation;
};
// class1.cpp
#include "class1.h"
int Class1::rotation = 5.0f;
请注意 int Class1::rotation = 5.0f;
在程序初始化时发生一次。
我不知道您是否在遵循一些教程,他们是如何创建这个 class 的,但是您的静态成员数量令人担忧。这是一个 OOP 问题。如果你想制作许多 objects/instances 个 OOPExample,你需要了解静态的含义。在 class 的上下文中,当您将 static 关键字应用于变量时,这意味着所有 OOPExample objects 将共享该变量。这使得静态成员变量适用于默认值和给定的数字 class 之类的东西。您可以使用 static int OOPExample::count;
来计算您创建的 OOPExample objects 的数量。我稍后会把它放在一个例子中。
link 错误的原因可能有很多,尤其是缺少定义。 PcAF 在您的问题的评论中强调了一个重要的问题。但您也可能缺少 SFML 库。我依稀记得 SFML 教程,其中包括有关如何 link 在您的环境中使用它们的库的详细说明。在 VS 中,它将位于您的项目属性中的某个位置。如果你在 header 中声明了一些不在实现中的东西(通常是 cpp),你显然会得到类似的错误。您的静态变量就是这种情况,但也适用于函数。
现在你提供的三个文件有很多错误。我对它们进行了编辑以突出一些问题,但它远非完美。我不会以这种方式处理它,因为 sf::CircleShape 已经是一个 object-orientated 实体。它包含您要实现的所有内容。从来没有 over-abstract 问题(我在某个时候也意识到我们正在旋转一个实心圆哈哈)。你真的应该按照建议得到一本好的教科书,并从 ground-up 开始。 SFML 是一个巨大的库,它会分散您对 C++ 基础知识的理解。 OOP 只是 C++ 的一个方面,您需要掌握所有 C++ 基础知识才能有效地使用 OOP。如果这样做,您将拥有最强大的可用抽象机制(在我看来)。
我的编辑如下,但实际上,这只是兔子洞有多深的演示(它变得更糟)。如何实例化 OOPExample 显示在 main.
// OOPExample.h
#ifndef OOPEX_H
#define OOPEX_H
// Only include what you need to. Users of this header should be exposed to as
// little SFML as possible.
#include <SFML/Graphics/CircleShape.hpp>
class OOPExample{
public:
// Parameterless constructor.
OOPExample(); // Note, this sets the rotation to the default rotation.
// One that takes a initial rotation.
OOPExample(float initial_rotation);
// Rotate 0.1f (by default) or by user specified amount.
void rotate(float rotation = 0.1f);
// window.draw() takes a Drawable as its first argument. Fortunately,
// CircleShape is a shape which in turn is a Drawable. Notice that we
// return by constant reference. Callers cannot edit our shape but they
// get a reference to the sf::CircleShape shape instance so they can read
// it.
// const, & (i.e. reference), pointers requires a deep understanding of
// object ownership, copying by value, by reference, and now of
// particular interest in C++11, moving.
const sf::CircleShape &getShape() const;
// You forgot to declare and define this.
void setRotation(float rotation);
// Set the default rotation for all objects created with the
// parameterless constructor.
static void setDefaultRotation(float rotation);
// The destructor.
virtual ~OOPExample();
private:
sf::CircleShape shape;
// sf::CircleShape already has a rotation with getters and setters.
// Don't over abstract!
// Our setRotation, rotate functions seem a bit unneccesary.
// float rotation;
// Defaults.
static sf::CircleShape default_circle;
static float default_rotation;
// Count example.
static int count;
};
#endif // OOPEX_H
// OOPExample.cpp
// Personally, and I know with most other C++ developers, I prefer my header's
// extension to be .h. .hpp usually identifies headers with
// implementations/definitions of classes in the header file itself (necessary
// in some circumstances).
#include "OOPExample.h"
//
// How to initialise static member variables. This happens once at the
// beginning of the program.
//
// All our circles have a default radius of 5.
sf::CircleShape OOPExample::default_circle = sf::CircleShape(5);
// And rotation of 0.
float OOPExample::default_rotation = 0;
int OOPExample::count = 0;
// The definition of the parameterless constructor.
OOPExample::OOPExample()
// A class initialiser list. How we build a new object.
: shape(default_circle) // We copy the default circle.
{
// Do other stuff to construct the object if you need to. For example:
shape.setFillColor(sf::Color::Red);
setRotation(default_rotation);
count++; // We just made another OOPEXample instance.
}
// The definition of a constructor that takes an initial rotation. I just
// realised we are rotating a circle!
OOPExample::OOPExample(float initial_rotation)
: shape(default_circle) // We copy the default circle.
{
// Do other stuff to construct the object if you need to. For example:
shape.setFillColor(sf::Color::Red);
// Notice: we used the user provided argument this time.
setRotation(initial_rotation);
count++; // We just made another OOPEXample instance.
}
void OOPExample::rotate(float rotation)
{
shape.rotate(rotation);
// return; // No need to specify a return for a void.
}
const sf::CircleShape &OOPExample::getShape() const
{
return shape;
}
void OOPExample::setRotation(float rotation)
{
shape.setRotation(rotation);
}
void OOPExample::setDefaultRotation(float rotation)
{
// OOPExample scoping is unnecessary.
OOPExample::default_rotation = rotation;
}
OOPExample::~OOPExample()
{
// Do things required for cleanup, i.e. deinit.
// One OOPExample just reached the end of its lifetime. Either it
// was deleted or reached the end of the
// scope (i.e. {}) it was created in.
count--;
}
// main.cpp
#include "OOPExample.h"
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
// Call the default, parameterless, constructor to instantiate an object
// of OOPExample.
OOPExample oopexample;
// Create another with a initial rotation of your choosing.
OOPExample another_obj(0.5f);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
// The instance object of OOPexample is referred to by oopexample.
// window.draw(oopexample().shape);
// This member is now private.
//window.draw(oopexample.shape);
window.draw(oopexample.getShape());
window.display();
}
return 0;
}