I have two simple classes, very simple One is like master table and contains list of pointers to class Two, and class Two contains one pointer to class One. In every class there is function which call methods over pointers, but I am getting error like
error C2027: use of undefined type
---- class One.h"
#include "Two.h"
class One {
public:
list<Two*> something;
void t(){pointer on Two call methods}
};
and
---------class Two.h
class One;
class Two {
public:
One* something;
void t(){pointer on One call methods}
};
How to solve this problem ?
Move your method defenition to .cpp and include the required header with the type defenition.
Two.h
class One;
class Two {
public:
One* something;
void t();
};
Two.cpp:
void Two::t() {...}
This is required because compiler is not able to generate the code for calling a method of an undefined type
Related
im learing c++.I was goofing around trying new stuff and wanted to use an object class sub in class object.But i was getting error saying that the object of class sub not in not defined.I know how to solve this issue i just have to move class sub above class object so that the compiler knows that there is a class called sub.
But I feel like this will get annoying as my code grows bigger and bigger so i tried forward declaring class like we do for function prototyping.But this doesn't work as it gives me this error -
'object::thing' uses undefined class 'sub'
Here is the code -
#include <iostream>
#include <vector>
class sub;
class object;
class object
{
private:
sub thing;
int ray;
public:
void set(int n);
void get() const;
};
class sub
{
public:
int num;
public:
void set_num(int n);
void get_num() const;
};
int main()
{
object ray;
ray.set(4);
ray.get();
}
Can you guys help me out??
thanks
When a type is used in c++, at a minimum that type needs to have been declared previously.
However, in some cases, the type needs to be defined (complete) as well.
class A;
class B {
A a; // error, because A needs to be defined
};
In other cases, the type only needs to be declared (i.e. it can be incomplete):
class A;
class B {
A *a; // fine, because A only needs to be declared
};
If a type needs to be defined when it's used (as in your case), then you have no choice but to define it before hand. You could put the definition in a header file, but that file still needs to be included before the type is used.
I have three .h and three .cpp files along with them.
I have made an object of a class in the first .h (say 1.h) in a class that is in 2.h. I want to use that class object in my 3.cpp.
1.h
class One
{
bool pressed;
...
}
2.h
#include "1.h"
Class Two
{
public:
One object;
...
}
3.h
#include "2.h"
Class Three
{ ...
}
3.cpp
#include "3.h"
void Three::OnPressed()
{
object.pressed = true;
}
It allows me to make the object without complaints, however, my program gives this error when run:
error C2065 'object': undeclared identifier
I don't think this is a hard question, but I had trouble trying to explain my problem through a search bar. If you could help me out I'd appreciate it.
OnPressed() is a member of Three, but Three does not derive from Two, so Three does not have any object member that OnPressed() can access. That is what the compiler is complaining about.
You would need to either:
make Three derive from Two
class Three : public Two
give Three a member that is an instance of One (just like you did with Two):
class Three
{
public:
One object;
void OnPressed();
...
};
void Three::OnPressed()
{
object.pressed = true;
}
Or give it an instance of Two:
class Three
{
public:
Two object2;
void OnPressed();
...
};
void Three::OnPressed()
{
object2.object.pressed = true;
}
I have quick question regarding incomplete types and unique_ptr.
I was trying to have a simple tree kinda structure which has been simplified here and I was getting a few compiler errors about incomplete types and what I knew was that I have to define the dtor which makes. Though that did not solve the issue, at least in msvc that I am testing it.
What I instead had to do was that for every class that required destruction of the incomplete types I had to just include the relevant header in the .cpp file. Defining explicitly the dtor did not help which was surprising to me.
Level1.h
#include "Level2Vector.h"
class Level1
{
public:
Level1() : lvl2_vec(this) {}
private:
Level2Vector lvl2_vec;
};
Level1.cpp
#include "Level2.h" // this was needed to not get the incomplete type
#include "Level3.h" // this was needed to not get the incomplete type
Level2.h
#include "Level3Vector.h"
class Level1;
class Level2
{
public:
Level2(Level1* const lvl1) : parent_(lvl1), lvl3_vec(this){}
private:
Level1* parent_;
Level3Vector lvl3_vec;
};
Level2.cpp
#include "Level2.h"
#include "Level3.h" // this was needed to not get the incomplete type
Level3.h
class Level2;
class Level3
{
public:
Level3(Level2* const lvl2) : parent_(lvl2) {}
private:
Level2* parent_;
};
Level2Vector.h
class Level1;
class Level2;
class Level2Vector : public std::vector<std::unique_ptr<Level2>>
{
public:
Level2Vector(Level1* lvl1) : parent_(lvl1) {}
private:
Level1* parent_;
};
Level3Vector.h
class Level2;
class Level3;
class Level3Vector : public std::vector<std::unique_ptr<Level3>>
{
public:
Level3Vector(Level2* lvl2) : parent_(lvl2) {}
//~Level3Vector();
private:
Level2* parent_;
};
Am I missing something ?
Is every class that would potentially be using say Level2Vector need to include the Level2.h header ?
The type should be complete for the destructor, but the destructor is auto generated inline, so that mean that each place where the class is destroyed should have definition of the class own by std::unique_ptr.
The simpler to avoid this problem is to declare destructor for each class that have std::unique_ptr member. So:
class Level3Vector
{
public:
explicit Level3Vector(Level2* lvl2) : parent_(lvl2) {}
~Level3Vector();
// And so rule of 5
Level3Vector(const Level3Vector&) = delete;
Level3Vector& operator =(const Level3Vector&) = delete;
Level3Vector(Level3Vector&&) = default;
Level3Vector& operator =(Level3Vector&&) = default;
private:
std::vector<std::unique_ptr<Level3>> lvl3s;
Level2* parent; // or std::observer_ptr<Level2> parent;
};
And in cpp:
#include <Level3.h>
Level3Vector::~Level3Vector() = default;
Then destruction of Level3Vector in other classes doesn't require the include of <Level3.h>.
Generally speaking, you may use a forward-declared type (say in a header file you define a pointer using that type); but the definition of the type must be available before the definition of the type is needed. E.g. in Level1.h you define an object of type Level2Vector (not a pointer to Level2Vector!); so Level1.h must include Level2Vector.h.
With that in mind, let's examine your question "Does every class that would potentially be using Level2Vector need to include the Level2.h header?" The answer is no. Level2.h provides the definition of class Level2. So the correct way to look at it is: a file (using Level2Vector or not) needs to include Level2.h, if the file needs the definition of Level2.
I've two different classes (class1 class2) both of them have their own header and cpp files. Class2 has included the header of class1. Class1 has two structures which are public.
I want to call a method from class2 in class1 and to pass two pointers pointing on the structures.
The call of the method from class2 in class1. (obj is an object of class2 in class1):
obj.routine(ip_s.c_str(), &NLP_data_recv, &recv_data_data); //write to harddrive
Following the declaration of the method in class2:
int routine(std::string raw_data_re, struct NLP_data_header_package *Header_data, struct NLP_data_data_package *Data_data);
The following Error occurs:
“argument of type ""com::NLP_data_data_package *"" is incompatible with parameter of type ""NLP_data_data_package *""
How can I solve this problem? Thank you.
EDIT: Additional code:
class com header(class1):
#ifndef COM_H
#define COM_H
//...
#include "Dateiverwaltung.h"
//...
class com
{
private:
Dateiverwaltung obj;
//...
public:
int run(void);
com(std::array<std::string,TWO> socket);
~com();
struct NLP_data_header_package
{
//...
}NLP_data_recv;
struct NLP_data_data_package
{
//...
}recv_data_data;
class com cpp (class1)
//...
if (recv_command == DATA_COMMAND)
{
obj.routine(ip_s.c_str(), &NLP_data_recv, &recv_data_data); //write to harddrive
obj.ext_close_file();
}
//...
class Dateiverwaltung header(class2)
#ifndef DATEIVERWALTUNG_H
#define DATEIVERWALTUNG_H
//...
#include "communication.h"
//...
public:
Dateiverwaltung(char* directory_global_re);
~Dateiverwaltung();
int routine(std::string raw_data_re, struct NLP_data_header_package *Header_data, struct NLP_data_data_package *Data_data);
int ext_close_file(void);
//...
class Dateiverwaltung cpp (class2)
//...
int Dateiverwaltung::routine(string raw_data_re, struct NLP_data_header_package *Header_data, struct NLP_data_data_package *Data_data)
{
//...
The error says there's a "com::NLP_data_data_package"
and a "NLP_data_data_package"
That's two different classes (for the compiler), since they seem to be defined in different namespaces, namely com and the default namespace.
I'm trying to build a solution which has three files. With main.cpp it is four files.
Entity.h
#pragma once
#include "SystemBase.h"
namespace Engine {
class Entity {
public:
Entity() { }
void s(SystemBase* sb) { }
};
}
SubscribersList.h
#pragma once
#include "SystemBase.h"
#include "Entity.h"
namespace Engine {
class SubscribersList {
friend SystemBase;
public:
SubscribersList() { }
void f(Entity* e) { }
};
}
SystemBase.h
#pragma once
#include "SubscribersList.h"
#include "Entity.h"
namespace Engine {
class SystemBase {
public:
SystemBase() { }
void g(Entity* e) { }
private:
SubscribersList m;
};
}
Don't focus on the body's of methods in the headers. It is just to keep things simple. I found two ways to build the solution.
1. Write the word class before all class names. But it crashes when I try to separate the realization from prototypes.
2. Write all code in one file.
I don't/won't write the keyword class before all class names to build the solution, and certainly I don't/won't write a big project in one file. So why I can't build it? What is the magic?!
To understand the problem of cyclic header dependency we first need understand the difference between a class declaration and definition and the concept of incomplete types.
A prototype or forward declaration of a type Type is written as:
class Type;
Such a forward declaration allows you to create pointers and reference to that type.
You cannot however instantiate, dereference pointers to or use a reference to Type until its full type is declared.
A declaration for Type could be written as:
class AnotherType;
class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};
Now we have the declaration instances can be created and pointers to Type can be dereferenced.
However before m_theOtherThing is dereferenced or instanciated AnotherType must be fully declared.
class AnotherType {
Type m_aType;
}
Should do, which gives us both the full declaration and definition of AnotherType.
That allows to continue on to write the definition of Type::aMemberFunc:
void Type::aMemberFunc() {
m_theOtherThing = new AnotherType();
}
If instead of presenting this code to the compiler in this order we instead presented the full declarations of Type and AnotherType up front:
class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};
class AnotherType {
Type m_aType;
}
Then AnotherType *m_theOtherThing; will fail to compile as AnotherType has not been declared or forward declared by that point.
Switching the order gives:
class AnotherType {
Type m_aType;
}
class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};
Now Type m_aType; will not compile as Type has not been declared. A forward declaration would not do in this case.
Using #pragma once instead of header guards does not in anyway change the problem. #pragma once only ensures the header is include just once it does not effect the order the compiler processes the code otherwise. It certainly does not allow the compiler to ignore undefined types when it reaches them.
For this kind of class structure there is no way for the compiler to be able to process it without the use for forward declarations.