Alright, so I've tried a few ways to deal with this issue, but I can't seem to fix it.
In my header file I have:
class MyClass {
public:
bool test;
struct MyStruct;
};
I also have a constructor and all that, but that's not the important/not causing errors
In the cpp what I want to do is this:
MyClass::MyStruct {
test=true;
};
The problem with this, is that the struct is unable to access the test variable. How can I pass the current instance's variable to the struct or some other way to allow the struct to access the variable.
This:
MyClass::MyStruct {
test=true;
};
Is not at all valid C++ code. Perhaps you meant this:
MyClass::Class() {
test=true;
}
Which would make a default constructor of MyClass which sets test to true. But your question makes it seem like you want to set the value of MyClass::test from MyClass::MyStruct. This is not really possible, because a nested class (or struct, in your case) does not "inherit" or "contain" or really have almost any special relationship with its enclosing class (or struct).
Another possibility is this:
class MyClass {
public:
static bool test;
struct MyStruct;
};
MyClass::MyStruct::MyStruct() {
test=true;
}
Which would make a default constructor of the nested struct which sets a variable in the enclosing class, but the variable then needs to be static, meaning there's only one in the whole program, not a separate value per instance of either class or struct.
Seems to me if MyStruct is executing code it should be a class. And if so, you either pass it an instance of the MyClass (e.g. this if calling from MyClass), or pass it a reference to the member it needs (e.g. this->test)...
You can declare the structure as a friend in the class definition.
class MyClass {
public:
bool test;
friend struct MyStruct;
};
Edit:
class MyClass {
friend class MyStruct(MyClass *myClass) : myClass(myClass) {
private:
MyClass *myClass;
}
MyStruct *myStruct;
bool test;
public:
MyClass() {
myStruct = new MyStruct(this);
}
}
Note: This is untested and just written in my browser. I know it's missing destructors and stuff.
Since you're passing the parent pointer to the member class, the member class can then access the parent class's private members because it was declared a friend.
Related
class Class1 //Would be object mClass1
{
public:
void Function1()
{
a++;
}
private:
int a = 0;
Class2 mClass2;
}
(Editing in a space here to clarify Class2 is not defined after Class1; they are in separate files.)
class Class2 //Would be object mClass2
{
public:
Function2()
{
Function1(); // Would be from mClass1
}
}
So Class1 creates an instance of a Class2 object, and that Class2 object has a member function that wants to access the "parent" object's member function, without using inheritance.
I don't know what I specifically need to search for to learn about this. Does it have to do with dereferencing a new pointer? Constructor type/initialization? Does it have a terminology? "Nested classes" bring up classes defined inside another class, which is not what this is.
Without inheritance there is no way to get the 'parent class'. So instead you should just pass the function as a parameter, maybe in the constructor of class 2 if you use it multiple times. See for example: https://www.cprogramming.com/tutorial/function-pointers.html
You cannot do this. Class2 is not known yet when you define Class1, so the Class1::mClass2 data member cannot possibly be created. But this problem can be solved by defining Class2 before Class1, and implementing Class2::Function2() outside the class and only after Class1.
As for calling Function1() inside Function2(), Class2 needs to know the object on which to call Function1(). You could use a reference member for that that you initialize in the constructor:
// Forward-declaration of Class1 so that Class2 will be able to define
// references or pointers to Class1.
class Class1;
class Class2
{
public:
// Constructor that requires a reference to our parent object.
explicit Class2(Class1& parent)
: parent_(parent)
{ }
// Just declare the function. We need to implement it later, outside
// this class definition because Class1 is not fully known yet and as
// a result we can't have calls to Function1() because the compiler
// doesn't know that function yet.
void Function2();
private:
// This is just a reference, so it works even if Class1 is not fully
// known yet.
Class1& parent_;
};
class Class1
{
public:
void Function1() { /* ... */ }
private:
int a = 0;
Class2 mClass2{*this}; // Pass ourself as the parent object.
};
// Class1 is fully known now, so we can do calls to Function1().
inline void Class2::Function2()
{
parent_.Function1();
}
This will work, but it has an important implication: it disables the assignment operator of Class2. This is probably what you want in this case, because two copies of Class2 should probably not have the same Class1 parent object.
However, I don't see why you need to do this. It complicates matters for no good reason. Why not simply pass the Class1 object that Function2() should use as a function argument instead? So:
class Class1;
class Class2
{
public:
void Function2(Class1& c1_obj);
};
class Class1
{
public:
void Function1() { /* ... */ }
private:
int a = 0;
Class2 mClass2;
};
inline void Class2::Function2(Class1& c1_obj)
{
c1_obj.Function1();
}
So whenever Class1 needs to call Class2::Function2(), just pass *this to it. It's simpler and doesn't have the drawbacks of holding a reference or pointer to another object.
With canonic classes - no way to do this, because Class2 is incomplete within Class1 and if you declare Class2 inside of Class1 (as a nested class), it wouldn't have access to Class1, because Class1 incomplete!
Looks like an unsolvable paradox? It is unsolvable in OOP land, but can be dodged just like Nikos had shown. But the problem of undefined types in some cases can be resolved in C++ or similar concept-oriented languages by using CRTP - Curiously recurring template.
If it is possible or not in your use-case and how complex it would be depending on what purpose you pursue. Here is an example of a paradoxical CRTP behavior - a member of base class is able to call a member of derived class:
#include <iostream>
template < class T>
class Base {
public:
template <class U>
struct Accessor : public U {
static void evoke_foo( T& obj)
{
return (obj.*(static_cast< void(T::*)() >(&Accessor::foo))) ();
}
};
void evoke( )
{
Accessor<T>::evoke_foo( *static_cast<T*>(this) );
}
};
class Derived : public Base<Derived> {
protected:
void foo() { std::cout << "Foo is called" << std::endl; }
};
int main()
{
Derived a;
a.evoke(); // evoke belongs to base.
}
Now if we'd want to determine return type of foo() automatically here, this would become an insanely complex piece of code. Some problems like that are solved in implementations of standard namesake of evoke method.
class myClass
{
private:
struct myStruct
{
int width = 0;
};
public:
myClass();
void changeValue();
};
myClass::myClass()
{
myStruct aStruct;
aStruct.width = 24;
}
void myClass::changeValue()
{
aStruct.width = 23;
}
I made the simple code above in order to test classes. In the member function changeValue i get the error saying that aStruct is not defined. But i don't really understand why it says it's undefined. Previously when i worked with classes this kind of code has worked fine. The difference between then and now is that in the class constructor i used pointers. So does this type of code only work for pointers and not for structs?
The reason i want this to work is it would be really usefull to have this "global" object that belongs to the class that is a struct.
This is not trouble with "understanding classes". You should go back and understand what "scope" is, which is one of basic concept of C++ language.
myStruct aStruct;
belongs to scope of member function myClass::myClass() and ceases to exist when execution of that function ends. This is completely different scope, aStruct variable doesn't exist there.
void myClass::changeValue()
{
aStruct.width = 23; // aStruct doesn't exist in any available scope
}
Now about declarations:
class myClass
{
private:
struct myStruct
{
int width = 0;
};
This code doesn't declare a struct storage inside of classmyClass. It declares member type myStruct (which is a class-type) inside of class myClass.
(Be wary of this name convention, it's very confusing. It's recommended to use capitalization like that only for members. Classes recommended to be all lower case or starting with capital letter.)
class myClass
{
private:
struct myStruct
{
int width = 0;
};
myStruct aStruct; // myClass got field aStruct
public:
myClass() : aStruct {24} {}
void changeValue();
};
aStruct here belongs to the private part of scope of class, which is available for all members of this class. myStruct is also declared as private so can't be used outside of class, be that in child class or just in outer scope.
myClass() : aStruct {24} {}
This is a non-trivial (user-defined) constructor with initializer list. aStruct is field of this class, so it can be initialized with a value like this. It is different from this form
myClass()
{
aStruct.width = 24;
}
In latter case, aStruct would be initialized first (with 0 in width field, as you had instructed) and its constructor will be called, then myClasss constructor would change value of its field to 24.
Before your question gets busted, you got to understand that everything in {} is scoped inside those braces, thus your problem here is that you have:
myStruct aStruct;
inside constructor. So aStruct is local variable to the constructor. In order to fix your code move it just below struct definition.
class myClass
{
private:
struct myStruct
{
int width = 0;
};
// MOVE IT HERE
myStruct aStruct;
public:
myClass();
void changeValue();
};
myClass::myClass()
{
aStruct.width = 24;
}
void myClass::changeValue()
{
aStruct.width = 23;
}
Now all member functions can access aStruct.
I would like to declare an instance of my class outer, then use that to declare an instance of outer's child class inner. In the project I'm working on, I would like to be able to declare several instances of an inner class, using different constructors. These instantiations should be able to access the private variables in outer. This example is a simplification of my problem. Can someone tell me what I'm doing wrong, or post a working example?
using namespace std;
#include <iostream>
class outer
{
private:
int x;
public:
outer(int input){x=input;};
class inner
{
public:
int showx(){cout<<outinst->x<<"\n";};
};
};
int main()
{
cout<<"hello julian\n";
outer* clevername(5);
//I can't make it work past this point. The desired efect is
//to declare an instance of outer initiated with a value of x,
//use this instance of outer to declare an instance of inner,
//then use this instance of inner to return the original value of x
clevername->inner* ins;
cout<<ins->showx()<<"\n";
};
The nested class (inner) is not automatically a data member of outer nor does an object of type outer::inner have any access to any private members of any object of type outer. Moreover, to access members of an object you need the . operator. Finally, you're confusing objects with pointers.
Here is an attempt at a code that does perhaps what you intended (not tried it so it may still need debugging).
#include <iostream>
class outer
{
const int x;
public:
outer(int input) : x(input) {}
class inner;
friend class inner; // inner must be friend to access private member x
class inner
{
const outer* const outinst; // const pointer to an outer object
public:
inner(const outer*out) : outinst(out) {}
int showx() const
{ return outinst->x; }
};
};
int main()
{
std::cout<<"hello julian\n";
outer clevername(5); // declare object of type outer
outer::inner ins(&clevername); // declare object of type outer::inner
std::cout << ins.showx() << "\n";
};
Note that there is no benefit or other use of the fact that outer::inner is a member type of outer, i.e. the same effect could have been achieved (more easily) by declaring inner as another freestanding class.
This
clevername->inner* ins;
is wrong. Use
outer::inner ins;
instead. BTW you have also incorrect clevername declaration, it does not declare an object but a pointer. Do not use pointers unless you know what you are doing.
For a code like this:
class foo {
protected:
int a;
public:
class bar {
public:
int getA() {return a;} // ERROR
};
foo()
: a (p->param)
};
I get this error:
invalid use of non-static data member 'foo::a'
currently the variable a is initialized in the constructor of foo.
if I make it static, then it says:
error: 'int foo::a' is a static data member; it can only be initialized at its definition
However I want to pass a value to a in the constructor.
What is the solution then?
In C++, unlike (say) Java, an instance of a nested class doesn't intrinsically belong to any instance of the enclosing class. So bar::getA doesn't have any specific instance of foo whose a it can be returning. I'm guessing that what you want is something like:
class bar {
private:
foo * const owner;
public:
bar(foo & owner) : owner(&owner) { }
int getA() {return owner->a;}
};
But even for this you may have to make some changes, because in versions of C++ before C++11, unlike (again, say) Java, a nested class has no special access to its enclosing class, so it can't see the protected member a. This will depend on your compiler version. (Hat-tip to Ken Wayne VanderLinde for pointing out that C++11 has changed this.)
In C++, nested classes are not connected to any instance of the outer class. If you want bar to access non-static members of foo, then bar needs to have access to an instance of foo. Maybe something like:
class bar {
public:
int getA(foo & f ) {return foo.a;}
};
Or maybe
class bar {
private:
foo & f;
public:
bar(foo & g)
: f(g)
{
}
int getA() { return f.a; }
};
In any case, you need to explicitly make sure you have access to an instance of foo.
The nested class doesn't know about the outer class, and protected doesn't help. You'll have to pass some actual reference to objects of the nested class type. You could store a foo*, but perhaps a reference to the integer is enough:
class Outer
{
int n;
public:
class Inner
{
int & a;
public:
Inner(int & b) : a(b) { }
int & get() { return a; }
};
// ... for example:
Inner inn;
Outer() : inn(n) { }
};
Now you can instantiate inner classes like Inner i(n); and call i.get().
You try to access private member of one class from another. The fact that bar-class is declared within foo-class means that bar in visible only inside foo class, but that is still other class.
And what is p->param?
Actually, it isn't clear what do you want to do
Your Question is not clear but there is use case when you will get this issue .
Invalid use of non-static data member.
When you are using "non-static data member in another class try to not use with scope resolution operator
Example::className::memberData = assignivalue ;
instead of above try to use object of className class;
Example:: m_pClassName->memberData=assignValue;*
If I have the following
class A
{
public:
int stuff;
void helper(B temp, int d); //what about here? I'm getting a 'B' has not been declared error here.
private:
class B
{
public:
int stuffer;
private:
int x;
};
}:
Whats the correct way to refer to class 2 in my implementation file? Would it be
1::2::someMethod? Or 2::someMethod?
Assuming that 1 and 2 refer to REAL class names, 1::2::methodName just like any other nested scoping.
First of all, class name cannot start with integer. So renaming them:
class A
{
public:
int stuff;
private:
class B
{
public:
int stuffer;
private:
int x;
};
};
Second, since the nested class B is in the private section, so you cannot access it from outside the scope of class A. B is accessible to A only. And the syntax of declaring an object of type B would be B bObj; in the scope of A.
Now you should try yourself first, before asking futher questions!
As for your edit (the added question): it's not compiling because by the time the compiler sees B temp, it has not yet seen the definition of B, that is why it says B is not declared!
The fix is very simple. Declare B before it's used, something like this:
class A
{
private:
class B
{
public:
int stuffer;
private:
int x;
};
public:
int stuff;
void helper(B temp, int d);
}; //<--- this is also fixed. your code has 'colon', instead semi-colon!
Also read the comment at the end of the class!
If you're inside a method of class 1, you can use 2::somemethod. In other places, use 1::2::somemethod. "Inside" includes method argument declarations in method implementations of class 1, but not return value declarations for method implementations of class 1.
It depends on which scope level you're at. Inside a member function for class 1, it would be class_2::someMethod. At file scope, it would be class_1::class_2::someMethod. It's always correct to fully qualify a function or variable name like that, but sometimes it's more typing than is strictly necessary. In general, you need the scope resolution operator :: when the compiler can't figure out on its own what you're referring to.
In practice, the best way to find out is try it and see what happens. If the compiler gives you an error, throw the class name in front of it and try again.
Syntax for nested class:
Class class_name1
{
Private:
Data members
Public:
Member functions
{
.........
}
Class class_name2 //class2 is embedded with class1
{
Private:
Data members
Public:
Member functions
{
.........
}
}; // class2
}; //class1
Nested class is possible to define one class within another class since a class declaration does,define a scope.
A nested class is valid only within the scope of the enclosing class.
Need of nested class is virtually not existed.