Having trouble understanding classes c++ - c++

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.

Related

Why can we only initialize structs with primitive types or pointers?

class MyClass {
};
struct myStruct {
MyClass instance;
};
struct myStructReference {
MyClass& instance;
};
struct myStructPointer {
MyClass* instance;
};
int main() {
// EDIT: works!
myStruct b;
// also doesn't work
// myStructReference c;
// works
myStructPointer d;
}
The error I get is: 'myStructReference::myStructReference()' is implicitly deleted because the default definition would be ill-formed:.
It appears as though C++ goes through the motions of creating a default constructor for a struct, but then fails. I suppose this makes sense, since a struct is nearly identical to a class under the hood, just struct has all default public members + inheritance.
Is it because we can automatically assign a pointer to initialize as NULL, whereas we can't with a reference?
Asking to learn!
myStructReference::instance is, well, a reference. References MUST always be initialized. In this case, you reference is not initialized, so it won't compile.

Accessing Class Data from Declared Struct

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.

Why can't I define variables in classes?

Whenever I define a variable and give it a value at the same time inside a class, I get an error. What is the reason for this?
As you can see, this doesn't work...
class myClass {
private:
int x = 4; // error
};
But when I keep the variable undefined it does:
class myClass {
private:
int x;
};
Since no one else is using member initialization, I'll introduce you:
class myClass {
private:
int x;
public:
myClass() : x (4){}
};
It's always better to use this over assigning in the body of the constructor, since by the time the body begins, all user-defined members will have already been initialized whether you said so or not. Better to do it once and actually initialize the non-user-defined members, and it is the only method that works for both non-static const members, and reference members.
For example, the following will not work because x isn't being initialized in the body, it's being assigned to:
class myClass {
private:
const int x;
public:
myClass() {x = 4;}
};
Using a member initializer, however, will, because you're initializing it off the bat:
class myClass {
private:
const int x;
public:
myClass() : x (4){}
};
Note also that your int x = 4; syntax is perfectly valid in C++11, where it subs in for any needed initialization, so you'll benefit if you start using it.
Initialize your variables in the constructor.
class myClass {
private:
int x;
public:
myClass()
{
x = 4; // hope that it will work
}
};
Updated Answer:
According to chris, it is better to use member initialization
class myClass {
private:
const int x;
public:
myClass() : x (4){}
};
Instance variable are supposed to be defined using setter methods, IE: setX(input) or inside a constructor.
Do this insted:
class myClass
{
private:
static const int x = 4;
};
If you don't x to be either static or constant, use only int x; instead and initialize x in the constructor of the class.
Your class is like a blue print. It does not have any storage associated with it. When you instantiate an object of your class, that is akin to the building based on that blue print. Your object has storage and that can hold the value you give to the member variables.
Also, as others have pointed out, it is possible to do what you want in C++11. Check out:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm
In C++03,
only static const integral data members can be initialized within a
class.
Either initialize in the constructor, or make the data member static const:
class myClass {
private:
int x;
public:
myClass() {
x = 4;
}
};
or
class myClass {
private:
static const int x = 4;
};

invalid use of non-static data member

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;*

Any workarounds for non-static member array initialization?

In C++, it's not possible to initialize array members in the initialization list, thus member objects should have default constructors and they should be properly initialized in the constructor. Is there any (reasonable) workaround for this apart from not using arrays?
[Anything that can be initialized using only the initialization list is in our application far preferable to using the constructor, as that data can be allocated and initialized by the compiler and linker, and every CPU clock cycle counts, even before main. However, it is not always possible to have a default constructor for every class, and besides, reinitializing the data again in the constructor rather defeats the purpose anyway.]
E.g. I'd like to have something like this (but this one doesn't work):
class OtherClass {
private:
int data;
public:
OtherClass(int i) : data(i) {}; // No default constructor!
};
class Foo {
private:
OtherClass inst[3]; // Array size fixed and known ahead of time.
public:
Foo(...)
: inst[0](0), inst[1](1), inst[2](2)
{};
};
The only workaround I'm aware of is the non-array one:
class Foo {
private:
OtherClass inst0;
OtherClass inst1;
OtherClass inst2;
OtherClass *inst[3];
public:
Foo(...)
: inst0(0), inst1(1), inst2(2) {
inst[0]=&inst0;
inst[1]=&inst1;
inst[2]=&inst2;
};
};
Edit: It should be stressed that OtherClass has no default constructor, and that it is very desirable to have the linker be able to allocate any memory needed (one or more static instances of Foo will be created), using the heap is essentially verboten. I've updated the examples above to highlight the first point.
One possible workaround is to avoid the compiler calling the OtherClass constructor at all, and to call it on your own using placement new to initialize it whichever way you need. Example:
class Foo
{
private:
char inst[3*sizeof(OtherClass)]; // Array size fixed. OtherClass has no default ctor.
// use Inst to access, not inst
OtherClass &Inst(int i) {return (OtherClass *)inst+i;}
const OtherClass &Inst(int i) const {return (const OtherClass *)inst+i;}
public:
Foo(...)
{
new (Inst(0)) OtherClass(...);
new (Inst(1)) OtherClass(...);
new (Inst(2)) OtherClass(...);
}
~Foo()
{
Inst(0)->~OtherClass();
Inst(1)->~OtherClass();
Inst(2)->~OtherClass();
}
};
To cater for possible alignment requirements of the OtherClass, you may need to use __declspec(align(x)) if working in VisualC++, or to use a type other than char like:
Type inst[3*(sizeof(OtherClass)+sizeof(Type)-1)/sizeof(Type)];
... where Type is int, double, long long, or whatever describes the alignment requirements.
What data members are in OtherClass? Will value-initialization be enough for that class?
If value-initialization is enough, then you can value-initialize an array in the member initialization list:
class A {
public:
A ()
: m_a() // All elements are value-initialized (which for int means zero'd)
{
}
private:
int m_a[3];
};
If your array element types are class types, then the default constructor will be called.
EDIT: Just to clarify the comment from Drealmer.
Where the element type is non-POD, then it should have an "accessible default constructor" (as was stated above). If the compiler cannot call the default constructor, then this solution will not work.
The following example, would not work with this approach:
class Elem {
public:
Elem (int); // User declared ctor stops generation of implicit default ctor
};
class A {
public:
A ()
: m_a () // Compile error: No default constructor
{}
private:
Elem m_a[10];
};
One method I typically use to make a class member "appear" to be on the stack (although actually stored on the heap):
class Foo {
private:
int const (&array)[3];
int const (&InitArray() const)[3] {
int (*const rval)[3] = new int[1][3];
(*rval)[0] = 2;
(*rval)[1] = 3;
(*rval)[2] = 5;
return *rval;
}
public:
explicit Foo() : array(InitArray()) { }
virtual ~Foo() { delete[] &array[0]; }
};To clients of your class, array appears to be of type "int const [3]". Combine this code with placement new and you can also truly initialize the values at your discretion using any constructor you desire. Hope this helps.
Array members are not initialized by default. So you could use a static helper function that does the initialization, and store the result of the helper function in a member.
#include "stdafx.h"
#include <algorithm>
#include <cassert>
class C {
public: // for the sake of demonstration...
typedef int t_is[4] ;
t_is is;
bool initialized;
C() : initialized( false )
{
}
C( int deflt )
: initialized( sf_bInit( is, deflt ) )
{}
static bool sf_bInit( t_is& av_is, const int i ){
std::fill( av_is, av_is + sizeof( av_is )/sizeof( av_is[0] ), i );
return true;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
C c(1), d;
assert( c.is[0] == 1 );
return 0;
}
Worth noting is that in the next standard, they're going to support array initializers.
Use inheritance for creating proxy object
class ProxyOtherClass : public OtherClass {
public:
ProxyOtherClass() : OtherClass(0) {}
};
class Foo {
private:
ProxyOtherClass inst[3]; // Array size fixed and known ahead of time.
public:
Foo(...) {}
};
And what about using array of pointers instead of array of objects?
For example:
class Foo {
private:
OtherClass *inst[3];
public:
Foo(...) {
inst[0]=new OtherClass(1);
inst[1]=new OtherClass(2);
inst[2]=new OtherClass(3);
};
~Foo() {
delete [] inst;
}
};
You say "Anything that can be initialized using only the initialization list is in our application far preferable to using the constructor, as that data can be allocated and initialized by the compiler and linker, and every CPU clock cycle counts".
So, don't use constructors. That is, don't use conventional "instances". Declare everything statically. When you need a new "instance", create a new static declaration, potentially outside of any classes. Use structs with public members if you have to. Use C if you have to.
You answered your own question. Constructors and destructors are only useful in environments with a lot of allocation and deallocation. What good is destruction if the goal is for as much data as possible to be allocated statically, and so what good is construction without destruction? To hell with both of them.