Проблема с включением заголовка класса, используемого в качестве члена внутри другого класса C ++ - PullRequest
1 голос
/ 13 декабря 2010

У меня проблема с определениями моих классов, возможно, из-за порядка включения или чего-то еще. Сообщение об ошибке, которое я получаю, -

g++ -I/opt/PDmesa/Mesa-5.0.1/include -I/opt/PDmesa/GLUT-3.7/include -c test.cpp
In file included from prog.h:16,
                 from test.cpp:10:
repeat.h:21: error: ‘Prog’ does not name a type
repeat.h:27: error: ‘Prog’ has not been declared
repeat.h: In constructor ‘Repeat::Repeat(float)’:
repeat.h:34: error: ‘in’ was not declared in this scope
repeat.h:34: error: ‘pg’ was not declared in this scope
repeat.h: In member function ‘virtual void Repeat::Run()’:
repeat.h:44: error: ‘class Repeat’ has no member named ‘pg’
make: *** [test.o] Error 1
% 

, поэтому вопрос, что мне делать, чтобы я мог использовать обаиз моих классов?main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>
#include <iterator>
#include "prog.h"
#include "window.h"


using namespace std;

Prog Turtle;

void draw(void)
{
    Turtle.Run();
}


int main ( int argc, char** argv )   // Create Main Function For Bringing It All Together
{
    filebuf fb;
    fb.open (argv[1],ios::in);
    istream input(&fb);
    input>>Turtle;
    fb.close();
    window w(argc,argv);
}

prog.h

#ifndef PROG_H
#define PROG_H

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>
#include <iterator>
#include "forward.h"
#include "left.h"
#include "right.h"
#include "jump.h"
#include "repeat.h"

using namespace std;

class Prog
{
    private:

    public:
        Prog();
        ~Prog();
        void Run();
        void clearbuff();
        vector<node*> listing;
        friend istream& operator>> (istream& in, Prog& pro);
};


Prog::Prog()
{
                                                                    //Default constructor
}

Prog::~Prog()
{
                                                                    //Default destructor
}

void Prog::Run()
{
    size_t sz=this->listing.size();
    for (size_t it=0;it<sz;it++)
            {
                node* ptr = this->listing.at(it);
                ptr->Run();
            }
}

void Prog::clearbuff()
{
    size_t sz=this->listing.size();
    for (size_t it=0;it<sz;it++)
            {
                node* ptr = this->listing.at(it);
                delete ptr;
            }
}

istream& operator>> (istream& in, Prog& pro)
{
    string tmp, command;
    double value;
    vector<string> text;
    while (in>>tmp)
    {
        for (size_t i=0;i!=tmp.size()+1;++i)
            tmp[i]=toupper(tmp[i]);
        text.push_back(tmp);
    }
    while (!text.empty())
    {
        command=text[0];
        istringstream inpStream(text[1]);
        float value = 0.0;
        if ((inpStream >> value)&&!text.empty())
        {
            if (command=="REPEAT")
                {
                unsigned int x(1), y(0), i(1), pos (0);
                text.erase (text.begin(), text.begin()+2);
                vector<string> reptext;
                if (text[0]=="[")
                {
                    for (i=1;(x!=y)&&i<=text.size();i++)
                        {
                            if (text[i]=="[")
                                ++x;
                            else if (text[i]=="]")
                                ++y;
                            reptext.push_back(text[i]);
                            pos=i;
                            }
                    reptext.erase(reptext.begin()+pos-1,reptext.end());
                    ofstream tempfile ("output.txt");
                    for(i=0; i<reptext.size(); i++)
                    tempfile << reptext[i] << endl;
                    tempfile.close();
                    filebuf rfb;        
                    rfb.open ("output.txt",ios::in);
                    istream rin(&rfb);  
                    pro.listing.push_back(new Repeat(value));
                    Prog ptm;
                    rin>>ptm;
                    rfb.close();
                    text.erase (text.end());
                    text.erase (text.begin(), text.begin()+3);
                }
                else
                cout << "not a bracket found after repeat command --problemo";
                }
            else if (command=="FORWARD")
                {
                    pro.listing.push_back(new Forward(value));
                    text.erase (text.begin(), text.begin()+2);
                }
            else if (command=="LEFT")
                {
                    pro.listing.push_back(new Left(value));
                    text.erase (text.begin(), text.begin()+2);
                }
            else if (command=="RIGHT")
                {
                    pro.listing.push_back(new Right(value));
                    text.erase (text.begin(), text.begin()+2);
                }
            else if (command=="JUMP")
                {
                    pro.listing.push_back(new Jump(value));
                    text.erase (text.begin(), text.begin()+2);
                }
            else
                cout << "Unknown command found in the input file!";
             //   text.erase(text.begin());
        }
        else
        {
            cout << " Value after command was not numeric or end of input file was reached!";
        }
    }
return in;
}

#endif // PROG_H

repeat.h

#ifndef REPEAT_H
#define REPEAT_H

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>
#include <iterator>
#include "command.h"
#include "prog.h"

using namespace std;

class Repeat : public command
{
    private:
        Prog pg;
        float repval;
    public:
        Repeat(float value);
        ~Repeat();
        void Run();
        friend istream& operator>> (istream& in, Prog& pro);
};

Repeat::Repeat(float value) : command(value)
{
        this->repval=value;

        for (int i=0;i<value;++i)
            in>>pg; //ctor
}

Repeat::~Repeat()
{

}

void Repeat::Run()
{
        this->pg.Run();
}

#endif // REPEAT_H

привет Я добавил отдельный .cpp для каждого заголовка, который требуетсяодин.теперь я получаю следующую ошибку

% make -f makefile3
g++ -I/opt/PDmesa/Mesa-5.0.1/include -I/opt/PDmesa/GLUT-3.7/include -c test.cpp
g++ -c forward.cpp
g++ -c left.cpp
g++ -c right.cpp
g++ -c jump.cpp
g++ -c repeat.cpp
g++ -c prog.cpp
g++ test.o -L/opt/PDmesa/Mesa-5.0.1/lib -L/opt/PDmesa/GLUT-3.7/lib -L/usr/X11R6/lib -lglut -lGLU -lGL -lX11 -lXext -lXmu -lXi -lm -o test
test.o: In function `draw()':
test.cpp:(.text+0x2ad): undefined reference to `Prog::Run()'
test.o: In function `main':
test.cpp:(.text+0x33a): undefined reference to `operator>>(std::basic_istream<char, std::char_traits<char> >&, Prog&)'
test.o: In function `__static_initialization_and_destruction_0(int, int)':
test.cpp:(.text+0x443): undefined reference to `Prog::Prog()'
test.cpp:(.text+0x448): undefined reference to `Prog::~Prog()'
collect2: ld returned 1 exit status
make: *** [test] Error 1

test.cpp

#include <iostream>
#include <fstream>
#include <sstream>
#include "prog.h"
#include "window.h"
using namespace std;

Prog Turtle;

void draw(void)
{
    Turtle.Run();
//  Turtle.clearbuff();
}


int main ( int argc, char** argv )   // Create Main Function For Bringing It All Together
{
    filebuf fb;
    fb.open (argv[1],ios::in);
    istream input(&fb);
    input>>Turtle;
    fb.close();
    window w(argc,argv);
}

prog.cpp

#include "prog.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include "forward.h"
#include "left.h"
#include "right.h"
#include "jump.h"
#include "repeat.h"

Prog::Prog()
{

}

Prog::~Prog()
{

}

void Prog::Run()
{
    size_t sz=this->listing.size();
    for (size_t it=0;it<sz;it++)
            {
                node* ptr = this->listing.at(it);
                ptr->Run();
            }
}

void Prog::clearbuff()
{
    size_t sz=this->listing.size();
    for (size_t it=0;it<sz;it++)
            {
                node* ptr = this->listing.at(it);
                delete ptr;
            }
}

istream& operator>> (istream& in, Prog& pro)
{
    string tmp, command;
    double value;
    vector<string> text;
    while (in>>tmp)
    {
        for (size_t i=0;i!=tmp.size()+1;++i)
            tmp[i]=toupper(tmp[i]);
        text.push_back(tmp);
    }
    while (!text.empty())
    {
        command=text[0];
        istringstream inpStream(text[1]);
        float value = 0.0;
        if ((inpStream >> value)&&!text.empty())
        {
            if (command=="REPEAT")
                {
                unsigned int x(1), y(0), i(1), pos (0);
                text.erase (text.begin(), text.begin()+2);
                vector<string> reptext;
                if (text[0]=="[")
                {
                    for (i=1;(x!=y)&&i<=text.size();i++)
                        {
                            if (text[i]=="[")
                                ++x;
                            else if (text[i]=="]")
                                ++y;
                            reptext.push_back(text[i]);
                            pos=i;
                            }
                    reptext.erase(reptext.begin()+pos-1,reptext.end());
                    ofstream tempfile ("output.txt");
                    for(i=0; i<reptext.size(); i++)
                    tempfile << reptext[i] << endl;
                    tempfile.close();
                    filebuf rfb;        
                    rfb.open ("output.txt",ios::in);
                    istream rin(&rfb);  
                    //pro.listing.push_back(new Repeat(value,rin));
                    Prog ptm;
                    rin>>ptm;
                    rfb.close();
                    for (int rp=0;rp<value;rp++)
                        {
                            cout << rp << endl;
                            for (i=0;i<ptm.listing.size();i++)
                                pro.listing.push_back(ptm.listing.at(i));
                        }
                    text.erase (text.end());
                    text.erase (text.begin(), text.begin()+3);
                }
                else
                cout << "not a bracket found after repeat command --problemo";
                }
            else if (command=="FORWARD")
                {
                    pro.listing.push_back(new Forward(value));
                    text.erase (text.begin(), text.begin()+2);
                }
            else if (command=="LEFT")
                {
                    pro.listing.push_back(new Left(value));
                    text.erase (text.begin(), text.begin()+2);
                }
            else if (command=="RIGHT")
                {
                    pro.listing.push_back(new Right(value));
                    text.erase (text.begin(), text.begin()+2);
                }
            else if (command=="JUMP")
                {
                    pro.listing.push_back(new Jump(value));
                    text.erase (text.begin(), text.begin()+2);
                }
            else
                cout << "Unknown command found in the input file!";
             //   text.erase(text.begin());
        }
        else
        {
            cout << " Value after command was not numeric or end of input file was reached!";
        }
    }
return in;
}

prog.h

#ifndef PROG_H
#define PROG_H

#include <iostream>
#include <fstream>
#include <vector>
#include "node.h"
using namespace std;

class Repeat;

class Prog
{
    private:

    public:
        Prog();
        ~Prog();
        void Run();
        void clearbuff();
        friend istream& operator>> (istream& in, Prog& pro);
        vector<node*> listing;
};

#endif // PROG_H

repeat.cpp

#include "repeat.h"
using namespace std;

Repeat::Repeat(float value, istream in) : command(value)
{
        this->repval=value;
        for (int i=0;i<value;++i)
            in>>pg; //ctor
}

Repeat::~Repeat()
{

}

void Repeat::Run()
{
        this-> pg.Run();
}

repeat.h

#ifndef REPEAT_H
#define REPEAT_H

#include <iostream>
#include <fstream>
#include "command.h"
#include "prog.h"
using namespace std;

class Prog;

class Repeat : public command
{
    private:
        Prog pg;
        float repval;
    public:
        Repeat(float value, istream in);
        ~Repeat();
        void Run();
        friend istream& operator>> (istream& in, Prog& pro);
};

#endif // REPEAT_H

, если я удаляю #include "prog.h" и все ссылки на Prog из теста, он компилируется правильно, но на самом деле он не работает.также то, что я на самом деле хочу сделать, это раскомментировать pro.listing.push_back(new Repeat(value,rin)); из prog.cpp и удалить следующие 10 строк. Эта строка была проблемой с предыдущим дизайном.Я предполагаю, что снова делаю что-то не так со всем заголовком

Ответы [ 4 ]

3 голосов
/ 13 декабря 2010

Проблема в том, что у вас есть циклические ссылки.

Вы можете думать о выражении #include как о простом вырезании и вставке содержимого этого файла в файл, в котором размещена директива.Есть несколько вещей, которые вы можете сделать.

# 1 - Поместите вашу реализацию в файл .cpp

В вашем определении класса Prog не упоминается Repeat.Если у вас есть файл prog.cpp с фактическими определениями методов, вы можете #include "repeat.h" там, и у вас не возникнет никаких проблем.

Другие приемы включают в себя предварительные объявления с использованием указателей в вашем классеопределение, где должна иметь место циклическая ссылка и т. д.

3 голосов
/ 13 декабря 2010
  1. Вы реализуете функции-члены для своих классов в заголовочных файлах. Не делайте этого. Вот для чего нужны файлы .cpp.

  2. У вас есть циркулярное включение. prog.h пытается #include "repeat.h", а repeat.h пытается #include "prog.h". Один из них будет обработан раньше другого, а затем охранники заголовков предотвратят обработку другого. В итоге вы не получите #include всего, что ожидали, и у вас пропадут объявления.

Это легко исправить, как только мы исправим первую проблему, потому что тогда нам больше не нужно будет знать о Repeat в заголовке Prog, и мы можем просто удалить этот оператор #include. В файле .cpp мы включаем оба заголовка, и проблем нет.

Я также хотел бы отослать вас к http://www.gamedev.net/reference/articles/article1798.asp, который подробно объясняет все распространенные проблемы с файлами заголовка и реализации.

2 голосов
/ 13 декабря 2010

В prog.h вы включаете repeat.h вверху файла.

Тело repeat.h не видит ни одного определения Prog.h.

Попробуйтеmain.cpp включает repeat.h напрямую Удаляет #include "repeat.h" из prog.h

1 голос
/ 13 декабря 2010

Я могу добавить, что если объявление обоих классов ссылается друг на друга, поэтому перемещение реализаций в файлы * .cpp не очень поможет (хотя это все еще необходимо), то вы должны были использовать предварительные объявления вместо включений, например это:

// in repeat.h
class Prog;
...
friend istream& operator>> (istream& in, Prog& pro);

// in prog.h
class Repeat;
...
void someMethodThatUsesRepeat(Repeat *rep);

Обратите внимание, что даже если у вас нет двух классов, ссылающихся друг на друга, использование предварительных объявлений может все же быть полезным для ускорения компиляции, поскольку компилятору не придется компилировать оба заголовка каждый раз, когда включен repeat.h.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...