开发者

Problem with header inclusion of a class used as member inside another class C++

开发者 https://www.devze.com 2023-01-30 21:08 出处:网络
I have a problem with the definitions of my classes, probably because of the inclusion order or something.the error msg i receive is

I have a problem with the definitions of my classes, probably because of the inclusion order or something.the error msg i receive is

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
% 

so the question what should I do so i can use both of my classes? 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

hello I added separate .cpp for each header that needs one. now I receive the following error

% 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 refere开发者_开发问答nce 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

if I remove #include "prog.h" and all references to Prog from test it compiles correctly but it doesnt actually work. also what I actually want to do is uncomment pro.listing.push_back(new Repeat(value,rin)); from prog.cpp and remove the next 10 lines.this line was the problem with the previous design. I supsect that Im doing again something wrong with the whole header thing


The problem here is that you have circular references.

You can think of a #include statement as simply cutting and pasting the contents of that file into the file where the directive is placed. There are several things you can do.

#1 - Put your implementation in a '.cpp' file

Your 'Prog' class definition does not mention Repeat. If you had a 'prog.cpp' file with the actual method definitions in it, you could #include "repeat.h" there and you wouldn't have any problems.

Other tricks include forward declarations, using pointers in your class defenition where a circular reference needs to take place, etc.


  1. You are implementing the member functions for your classes in the header files. Don't do that. That is what the .cpp files are for.

  2. You have a circular include. prog.h attempts to #include "repeat.h", and repeat.h attempts to #include "prog.h". One of these will get processed before the other, and then the header guards will prevent the other one from being processed. The net effect is that you don't end up #include ing everything you expected to, and then you have missing declarations.

This is easy to fix once we fix the first problem, because then we will no longer need to know about Repeat in the Prog header, and can just remove that #include statement. In the .cpp file, we include both headers, and there is no problem.

I would also like to refer you to http://www.gamedev.net/reference/articles/article1798.asp which explains all the common issues with header vs. implementation files in detail.


In prog.h you include repeat.h at the top of the file.

The body repeat.h doesn't see any of the Prog.h definitions.

Try having main.cpp include repeat.h directly Remove #include "repeat.h" from prog.h


I can add that if both classes' declaration referenced each other so moving the implementations to *.cpp files wouldn't really help (although it still would be necessary), then you should have used forward declarations instead of includes, like this:

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

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

Note that even if you don't have two classes referencing each other, using forward declarations may still be useful to speed up compilation since the compiler won't have to compile both headers each time when repeat.h is included.

0

精彩评论

暂无评论...
验证码 换一张
取 消