2016-04-16 55 views
-1

正如標題所示,我在C++中有一個OOP錯誤,LNK2001未解決的外部錯誤。這是我的代碼,我哪裏錯了? 我使用sfml在VS2015中使用圖形。C++ OOP LNK2001錯誤

// 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中錯誤地實例化類?

+0

我覺得你缺少'static float rot'的定義。 – PcAF

+0

你永遠不會定義任何靜態成員變量,你永遠不會實例化類('OOPExample oopexample();'是一個函數聲明 - 你也會得到鏈接錯誤)。我會推薦[這些]之一(http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)。 – molbdnilo

+0

謝謝,你可能知道,我來自純粹的OOP背景,所以C++還不是我的強項。 –

回答

1

對您的關於鏈接錯誤的問題。這些評論突出顯示了其中大部分......這些不是OOP錯誤,而是在您構建項目時發生鏈接時錯誤。我不知道你是否有編譯系統級語言的經驗;但學習編譯鏈接週期的基礎知識以及將最終程序放在一起時鏈接器所期望的內容將是一個不錯的主意。下面是一個如何定義靜態成員變量的簡單示例。

// class1.h 

Class1 
{ 
public: 
private: 
    static float rotation; 
}; 

// class1.cpp 

#include "class1.h" 

int Class1::rotation = 5.0f; 

請注意,int Class1::rotation = 5.0f;在程序初始化時會發生一次。

我不知道你是否按照一些教程,他們正在創建這樣的類,但你有一個令人擔憂的數量的靜態成員。這是一個OOP問題。如果你想製作OOPExample的許多對象/實例,你需要了解什麼是靜態方法。在類的上下文中,將static關鍵字應用於變量時,這意味着所有OOPExample對象將共享該變量。這使得靜態成員變量對於默認值和諸如給定類的數量這樣的東西都很有用。你可以用static int OOPExample::count;來計算你所做的OOPExample對象的數量。我將在稍後介紹一個例子。

鏈接錯誤可能有很多原因,特別是缺少定義。 PcAF在你的問題的評論中強調了一個重要的問題。但是你也可能會錯過SFML庫。我依稀記得SFML教程,包括關於如何在您的環境中鏈接其庫的詳細說明。在VS中,這將在您的項目屬性中的某處。如果你在頭文件中聲明瞭一些不在實現中的東西(通常是cpp),你會明顯得到類似的錯誤。您的靜態變量就是這種情況,但也適用於函數。

現在你提供的三個文件有很多錯誤。我編輯它們以突出一些問題,但它遠非完美。我不會以這種方式來處理它,因爲sf :: CircleShape已經是一個面向對象的實體。它具有您正在嘗試實施的所有功能。從來沒有過度抽象一個問題(我也意識到在某些時候,我們正在旋轉一個實心圓哈哈)。你應該真正按照建議來獲得一本好的教科書,並從頭開始。 SFML是一個巨大的庫,它會分散您對理解C++基礎知識的注意力。 OOP只是C++的一個方面,您需要擁抱所有C++基礎,纔能有效地使用OOP。如果你這樣做,你將擁有最強大的抽象機制(在我看來)。

我的編輯如下,但實際上,它只是一個演示兔子洞有多深(它變得更糟糕)。主要顯示如何實例化OOPExample。

// 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; 
}