C++程序结构

C++ program structure

本文关键字:结构 程序 C++      更新时间:2023-10-16

我在思考如何用C++构建程序时遇到了一些困难。我正在学习一本关于C++的书,有一次我们构造了两个类来解决一个问题。这本书最终将两个类以及它们的使用方式放在一个文件中并运行,这很有效。但我知道,结构更合理的代码会包括头文件,每个类都会有自己的文件,当我试图编译代码时,试图这样构建程序会造成问题。

我有两个来自其他语言的类,Token和Token_Stream,我知道Token和Tokon_Stream应该有自己的文件,每个都应该有一个声明文件。我的主要问题是:

Token_Stream需要了解Token。当一个Token_Stream被初始化时,它会初始化一个Token。我原以为在Token_Stream中只包含Token声明就足够了,这就足够了。但事实似乎并非如此。我对OOP语言编程有所了解,但Token_Stream并没有从Token继承任何东西,也不应该(我相信)它只需要知道足够的信息来初始化Token并存储它。我将包括以下每个相关文件:

令牌.h

// Token.h, declaration for Token
class Token
{
public:
    char kind;
    double value;
    Token(char ch);
    Token(char ch, double val);
}; //class Token

代币.cpp

// Token.cpp
#include "Token.h"
using namespace std;
Token::Token(char ch) 
    :kind(ch), value(0){}
Token::Token(char ch, double val)
    :kind(ch), value(val) {}

令牌流.h

// Token_Stream.h, declarations

class Token_Stream
{
public:
    Token_Stream();
    Token get();
    void putback(Token);
private:
    bool full; // do we already hold a token?
    Token buffer; // what Token do we hold?
};//class Token_Stream

令牌流.cpp

// Token_Stream.cpp implementation.
#include <iostream>
#include <stdexcept>
#include "Token.h" // needs to know what a Token is
#include "Token_Stream.h"
using namespace std;
/***********************************************************************
 * Token_Stream::Token_Stream()
 * 
 * Constructor for Token_Stream(), sets full = false and buffer as 0
 * Need to do :buffer(0), so we don't create an extra buffer variable
 **********************************************************************/
Token_Stream::Token_Stream()
:buffer(0)
{
    full = false; // nothing in our stream yet.
}//constructor
/***********************************************************************
 * void Token_Stream::put_back(Token t)
 * 
 * Given a token, we fill buffer and change full to true
 * 
 * Parameter: t - Token to fill buffer
 **********************************************************************/
void Token_Stream::putback(Token t)
{
    if(!full) // if its empty
    {
        buffer = t;
        full = true;
    }//if not full
    else
        throw runtime_error("buffer already full");
}// putback

/***********************************************************************
 * Token Token_Stream::get()
 * 
 * gets another token from input, or if we have one stored, gets that.
 * 
 * Returns: Token - next token in stream, either from buffer or from
 *                  input
 **********************************************************************/
Token Token_Stream::get()
{
    if(full) //if we already have something
    {
        full = false;
        return buffer;
    }
    //if we've reached here we haven't returned:
    char ch;
    cin>>ch; //get next input and switch over cases:
    switch(ch)
    {
        // if they input a valid character:
        case ';': 
        case 'q':
        case '(': case '+': case '*': case '-': case '/': case '%': 
        case ')':
            return Token(ch);
            break;
        //if they input a valid number, or lead with a decimal i.e., .5
        case '.': case '0': case '1': case '2': case '3': case '4': 
        case '5': case '6': case '7': case '8': case '9': 
        {
            cin.putback(ch);
            double val;
            cin>>val; //read it as a number
            return Token('8',val);
            break;
        }//case of valid number
        default:
            throw runtime_error("Bad Token");
    }//switch
}//get

这些就是文件,当我试图编译东西时,即在Token.cpp中放入一个空白的int main(){},一切都很好,我进行编译,如果我愿意,我可以在main()中运行东西

但是,当我尝试在Token_Stream.cpp中放入一个空白的int main(){}并尝试编译它时,它不起作用,我正在运行:

g++ -Wall -std=c++11 -o "Token_Stream" "Token_Stream.cpp" 

我甚至没有得到行号错误,但它声称对Token::Token(char)etc和其他Token构造函数有未定义的引用,所以我猜这意味着Token_Stream.cpp需要看到更多的Token.cpp,我该怎么做?我只是同时编译它们吗?

您需要将Token.cpp链接到可执行文件。

g++ -Wall -std=c++11 -o "Token_Stream" "Token.cpp" "Token_Stream.cpp"

否则,gcc将找不到Token构造函数的实现。

除了链接问题之外,如果您正在程序中寻找合适的结构,您仍然需要对依赖项进行排序。

Token_Stream.h应该这样开始:

// Token_Stream.h, declarations
#include "Token.h"  // Note that this include is at the top.
class Token_Stream
...

Token_Stream.cpp应该这样开始:

// Token_Stream.cpp implementation.
#include "Token_Stream.h"  // Note that this include is at the top.
#include <iostream>
#include <stdexcept>
...

以上要点是:

  1. 每个头文件都应包含在其实现文件的顶部
  2. 每个头文件都应该包括它实际需要的一切,而不是更多

这些先决条件将允许您的客户端在任何需要的地方包含您的标头。