C ++单独的头文件和源文件

时间:2017-02-11 09:21:30

标签: c++ header-files text-editor

我是C ++的新手,到目前为止,我已将所有代码都放在同一个文件中。 现在,随着我的进步,我需要将我的代码分离到我不熟悉的源文件和头文件中。

我可以使用简单的任务,但在这个程序中,我现在试图分成单独的文件给我一个错误,而当我把它全部放在一个文件中时,我可以编译它。

我卡在了错误消息

main.cpp:10:1: error: unknown type name 'textEditor'
textEditor siEditor;

如果有人能够解释我为什么会遇到这个错误并且如何防止它将不胜感激。我读到它可能与重复的声明有关,但我不明白从哪里来。

这是我的main.cpp看起来的样子:

#include <iostream>
#include <fstream>

using namespace std;

#include "textData.h"
#include "textEditor.h"

textData siData;
textEditor siEditor;

int main() 
{
    cout << "\nWelcome to siEdit!" << endl;
    while (true) 
    {
        cout << "\nWhat would you like to do? \nNew file = n, Append = a, View = v, Quit = q: ";
        string toDo;
        cin >> toDo;

        if (toDo == "n")
        {
            siEditor.openText();
            cout << "Now editing the file: " << siData.fileName.c_str() << endl;
            cout << "Type '=!' to stop editing and save. \n " << endl;
            siEditor.writeText();
        }

        else if (toDo == "a")
        {
            siEditor.appendTextOpen();
            cout << "Now appending text: " << siData.appendTextfileName.c_str() << endl;
            cout << "Type '=!' to stop editing and save changes. \n " << endl;
            siEditor.appendText();
        }

        else if (toDo == "v")
        {
            siEditor.readText();
            cout << "\n";
        }

        else if (toDo == "q")
        {
            return 0;
        }

        else 
        {
            cout << "Invalid input." << endl;
        }
    }
}

siEdit.cpp:

#include <iostream>
#include <fstream>

using namespace std;

#include "textData.h"
#include "textEditor.h"

textData siData;

class textEditor
{
    public: 
    void openText()
    {   
        //when associated file is open. 
        while (siData.siFile.is_open())
        {
            siData.siFile.close();
        }
        cout << "\nWhat do you want to call your file? ";
        cin >> siData.fileName;

        //Creates / Opens fileEditor
        const char* path = siData.fileName.c_str();
        siData.siFile.open(path);
    }

    void writeText()
    {
        bool editing = true;
        bool hasEditing = false;

        while (editing == true)
        {
            //Get user input
            string input = " ";
            getline(cin, input);
            string yesNo;

            if (input == "=!") 
                {   
                    cout << "Would you like to save the file? Y/N" << endl;
                    cin >> yesNo;

                    if (yesNo == "Y")
                    {
                        cout << "Filed saved: " << siData.fileName.c_str();
                        editing = false;
                    }   

                    else if (yesNo == "N")
                    {
                        cout << "No changes have been saved. Exiting." << endl;
                        hasEditing = false;
                        editing = false;
                        siData.siFile.clear();
                    }

                    else 
                    {
                        cout << "Invalid input. Type '=! to exit." << endl;

                    }
                }       

            else
            {
                siData.siFile << input;
                siData.siFile << endl;
                hasEditing = true;
            }
        }
    }


    void readText()
    {
        string line;
        cout << "\nEnter the name of your file: ";
        cin >> siData.fileName;
        cout << "\n";
        const char* path = siData.fileName.c_str();

        // input file stream
        //Internal stream buffer which performes I/O on file.
        ifstream siFileRead(path);
        if(siFileRead.is_open())
        {
            while(getline(siFileRead,line))
            {
                cout << line << endl;
                siData.siFile << line;
            }
        }

        else
        {
            cout << "Unable to open file. Confirm name and file location.";
        }
    }

    // open the existing text file
    void appendTextOpen()
    {
        while (siData.siFileAppend.is_open())
        {
            // erase previous text
            siData.siFileAppend.clear();
            // close the input text file
            siData.siFileAppend.close();
        }

        cout << "\nEnter the name of the file: ";
        //find file name.
        cin >> siData.appendTextfileName;

        //Makes / Opens file
        const char* path = siData.appendTextfileName.c_str();
        siData.siFileAppend.open(path, fstream::app);
    }

    //add text together with previous input.
    void appendText()
    {
        bool editing = true;
        bool hasEditing = false;

        while (editing == true)
        {
            //Gets user input
            string input = " ";
            getline(cin, input);

            if (input == "=!")
            {
                if (hasEditing == true)
                {
                    cout << "File saved: " << siData.appendTextfileName.c_str() << endl;
                    editing = false;
                }
            }

            else
            {
                siData.siFileAppend << input;
                siData.siFileAppend << endl;
                hasEditing = true;
            }
        }
    }
};

textData.h:

#ifndef SIEDITOR_H
#define SIEDITOR_H

class textData
{
    public: 
        string fileName;
        string appendTextfileName;
        ofstream siFile;
        ofstream siFileAppend;
};

#endif

textEditor.h:

#ifndef SIEDITOR_H
#define SIEDITOR_H

class textEditor
{
    public: 
    void openText()
    void writeText()
    void readText()
    void appendTextOpen()
    void appendText()
};


#endif

3 个答案:

答案 0 :(得分:2)

您在两个头文件中使用相同的包含保护,即SIEDITOR_H。这可以防止包含第二个标题的内容。使用#pragma once代替包含保护符号。

#pragma once事实上的标准supported by all compilers of practical interest

在您的实现文件中,不要重复类定义。只需定义声明的成员函数。还有static个数据成员,如果有的话。

答案 1 :(得分:1)

类只能定义一次。

将类定义移动到单独的头文件(连接以收集同名类的两个内容:字段和方法):

// textEditor.h
#pragma once
class textEditor {
  void appendText();
private:
    string fileName;
}

将类方法移动到单独的源文件:

// textEditor.cpp
#include "textEditor.h"
void textEditor::appendText() {
   // ... impl
}

在main.cpp中:

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

textEditor siEditor;

int main() 
{
  siEditor.appendText();
}

答案 2 :(得分:0)

考虑预处理器的作用。它会针对每个*.cpp文件单独运行,并处理您的所有#include#ifndef#define#endif语句。

这是您的main.cpp

的开头
#include <iostream>
#include <fstream>

using namespace std;

#include "textData.h"
#include "textEditor.h"

textData siData;
textEditor siEditor;

如果你是预处理器,你会如何预处理? [*] 你可能会从#include语句开始。中间结果将是:

// contents of <iostream>...
// contents of <fstream>...

using namespace std;

#ifndef SIEDITOR_H
#define SIEDITOR_H

class textData
{
    public: 
        string fileName;
        string appendTextfileName;
        ofstream siFile;
        ofstream siFileAppend;
};

#endif

#ifndef SIEDITOR_H
#define SIEDITOR_H

class textEditor
{
    public: 
    void openText()
    void writeText()
    void readText()
    void appendTextOpen()
    void appendText()
};


#endif

textData siData;
textEditor siEditor;

现在让我们检查一下这个中间结果:

// contents of <iostream>...
// contents of <fstream>...

using namespace std;

#ifndef SIEDITOR_H // <--- true, SIEDITOR_H is not defined, don't skip until #endif
#define SIEDITOR_H // <--- OK, SIEDITOR_H is now defined

class textData
{
    public: 
        string fileName;
        string appendTextfileName;
        ofstream siFile;
        ofstream siFileAppend;
};

#endif // <--- end of block started by #ifndef SIEDITOR_H

#ifndef SIEDITOR_H // <--- false, SIEDITOR_H is defined, skip until #endif
#define SIEDITOR_H

class textEditor
{
    public: 
    void openText()
    void writeText()
    void readText()
    void appendTextOpen()
    void appendText()
};


#endif // <--- end of block started by #ifndef SIEDITOR_H

textData siData;

预处理的结果是:

// contents of <iostream>...
// contents of <fstream>...

using namespace std;

class textData
{
    public: 
        string fileName;
        string appendTextfileName;
        ofstream siFile;
        ofstream siFileAppend;
};

textData siData;
textEditor siEditor; // error, unknown type textEditor

这解释了您一直在询问的具体错误消息。解决方案是在每个头文件中使用不同的include guard。您必须完全选择唯一包含警卫名称。在大项目中,这可能变得困难。这是一些阅读材料:

尽管如此,代码中还有更多错误:

首先,您的标头文件假设很多。他们认为其他人已经包含了必要的标准标题以获得std::stringstd::ofstream。他们假设其他人已使用using namespace std;using std::string; using std::ofstream;

这是非常糟糕的做法。您的标题文件应包含所需的标准标题,只需拼出完整名称(无using namespace std;)。

除此之外,还应使用 保证的标准标头来包含您需要的内容。如果您需要std::string,请添加<string>

标准标题可能包含其他标准标题,但只有极少数保证间接包含(如果<iostream>暗示<string>,我很难在标准中查找,但我想它不会。)

以下是一个例子:

<强> textEditor.h:

#ifndef SI_TEXT_DATA_H
#define SI_TEXT_DATA_H

#include <string>
#include <fstream>

class textData
{
    public: 
        std::string fileName;
        std::string appendTextfileName;
        std::ofstream siFile;
        std::ofstream siFileAppend;
};

#endif

最后,您重新定义textEditor中的siEdit.cpp课程。这是不允许的。您应该在类定义中的*.h文件中声明成员函数,并在*.cpp文件中定义成员函数。

textEditor.h应如下所示:

#ifndef SI_TEXT_EDITOR_H
#define SI_TEXT_EDITOR_H

class textEditor // class definition begins
{
    public: 
    void openText();       // declaration of member function
    void writeText();      // declaration of member function
    void readText();       // declaration of member function
    void appendTextOpen(); // declaration of member function
    void appendText();     // declaration of member function

}; // class definition ends

#endif

siEdit.cpp应如下所示:

#include "textData.h"
#include "textEditor.h"

textData siData;

void textEditor::openText() // definition of a member function begins
{   
    // ...

} // definition of a member function ends

// other definitions

你的全局变量(如textData siData;)也不是一个好主意,特别是看看它们是如何不包含在匿名命名空间中的。

[*] 实际的预处理器在技术上可能不会像这样工作,但你可以这样画面。