Go Down

Topic: [Solved] Pointer to class instances (Read 929 times) previous topic - next topic

sg80

Aug 07, 2012, 08:13 pm Last Edit: Aug 07, 2012, 09:15 pm by sg80 Reason: 1
Hello,

I'm actually a bit stuck. I need to have a pointer storing an instance of a derived class, but I can't figure out how to do so. Here some code followed by the error message which might help:

RootClass.h
Code: [Select]

#ifndef ROOT_H
#define ROOT_H

#include <WProgram.h>

class RootClass {
 public:
   RootClass();
   unsigned char currentValue;
   unsigned char valueCount;
};

#endif


RootClass.cpp
Code: [Select]

#include "RootClass.h"

RootClass::RootClass() {
 currentValue = 0;
 valueCount = 4; // some default value
}


Derived.h
Code: [Select]

#ifndef DERIVED_H
#define DERIVED_H

#include "RootClass.h"
#include <WProgram.h>

class Derived : public RootClass {
 public:
   Derived();
};

#endif


Derived.cpp
Code: [Select]

#include "Derived.h"

Derived::Derived() : RootClass::RootClass() {
 currentValue = 0;
 valueCount = 5; // will overwrite the default value (actually works)
}


sample.ino
Code: [Select]

#include "RootClass.h"
#include "Derived.h"

Derived a;
Derived b;

RootClass* current; // this is supposed to point to an instance of Derived, changing while the program is running

void setup() {
  Derived a();
  Derived b();

  current = &a; // FAILS: cannot convert 'Derived (*)()' to 'RootClass*' in assignment
}

// ...


What am I missing here?

EDIT:
Corrected name of constructor of Derived class.
Added [solved] to subject. :-)

PaulS

Code: [Select]
class DerivedClass : public RootClass {
  public:
    RootClass();
};

Why is the DerivedClass constructor called RootClass?

Code: [Select]
   Derived a();
   Derived b();

This is NOT how to create instances of the DerivedClass class (or the Derived class, for that matter). Loose the ();

Quote
What am I missing here?

You may need a cast, but, as the code posted won't even compile, its hard to say.

lloyddean

#2
Aug 07, 2012, 08:25 pm Last Edit: Aug 07, 2012, 08:28 pm by lloyddean Reason: 1
A valid pointer 'current' to instance 'a' once 'setup' is exited and the stack unwinds!

EDIT: An answer to the question: "What am I missing here?"

sg80

Thank you very much! That already helped a lot! Now I've got it working with this code:

Code: [Select]

#include "RootClass.h"
#include "Derived.h"

Derived a;
Derived b;

RootClass* current; // this is supposed to point to an instance of Derived, changing while the program is running

void setup() {
   Derived a;
   Derived b;
}

void loop() {
   current = &a;
   Serial.println(String(current->valueCount));
}

// ...


Two questions:

  • As my constructors might need to have some parameters later on, how am I going to pass them (since I need to omit the '()')?

  • Why can't I set the pointer in the setup-routine (where it might be well placed)?


WizenedEE


Two questions:

  • As my constructors might need to have some parameters later on, how am I going to pass them (since I need to omit the '()')?

  • Why can't I set the pointer in the setup-routine (where it might be well placed)?




1. You only omit the parentheses when there are no arguments. Otherwise:
Code: [Select]

myclass bob();

it looks like a function declaration called bob that takes no arguments and returns a myclass. On the other hand
Code: [Select]

myclass bob(3);

could not be a declaration because there need to be type names inside the parentheses when declaring a function.


2. You can, as long as you don't use it before it's set.

PaulS

Quote
Why can't I set the pointer in the setup-routine (where it might be well placed)?

Because the thing you are pointing to is a local variable that goes away (and gets deleted) when it goes out of scope. Then, you are left with a pointer that does not have the behavior you expect, since the place where ti points to no longer contains an instance of the class that you expect it to have.

sg80


Why can't I set the pointer in the setup-routine (where it might be well placed)?


2. You can, as long as you don't use it before it's set.


Which would happen - if I understand you right - because the first loop-call happens before the setup? I would never have guessed so. (?)

WizenedEE



Why can't I set the pointer in the setup-routine (where it might be well placed)?


2. You can, as long as you don't use it before it's set.


Which would happen - if I understand you right - because the first loop-call happens before the setup? I would never have guessed so. (?)


No, it doesn't. Sorry I misunderstood why you were asking -- PaulS' answer is correct.

sg80

Ah, now I understand! I've distinguished between the declaration and the construction - which was not correct. It works when I declare AND construct (in one step) the objects globally:

Code: [Select]

Derived a;
Derived b;
RootClass * current;

void setup() {
   current = &a
}

void loop() {
   Serial.println(String(current->valueCount));
   delay(200);
   current = &b;
   Serial.println(String(current->valueCount));
   delay(200);
}


...works fine.

THANKS again! :-)

PaulS

Quote
...works fine.

But doesn't prove anything. If you changed the valueCount field of a and b (by passing a value to the constructor or in setup), and saw that current->valueCount did indeed print differently as you change which object you point to, then you would have proven something.

Code: [Select]
  Serial.println(String(current->valueCount));
Don't make me come over there and slap you. There is absolutely no need to convert a char to a String so that the Serial.print() method can extract the char from the String to print it. A monumental waste of resources.

sg80

Well, in the actual program (not the example I posted) the proof has been made; but yes, I'm aware that the example is insufficient concerning that.

To justify myself for the waste of resources, I again need to refer to the difference between the example and my actual program, where not a Serial.print is called, but a function which expects a String. I apologize for that :)

PaulS

Quote
but a function which expects a String.

Your function? Rewrite to accept a char *, and get rid of the String class. There is a major bug in the free() function that String uses that can corrupt your program much sooner than was originally thought, considering how many times String calls malloc() and free() (to increase the size of a String by one char).

Quote
I apologize for that

Don't apologize. Change it.   8)

sg80

Uh oh, you were right, I'm running into memory-problems due to the usage of the String-class.

Is that a bug to be fixed in near future or will I need to find a different solution by myself? Where can I get more information about that issue? I could only find some 2 or 3 year old information about something similar (which seems to be fixed meanwhile).

I'm not very used to handling strings using char-arrays or char*s. Is there any good tutorial out there?

PaulS

Quote
Where can I get more information about that issue?

http://arduino.cc/forum/index.php/topic,115552.0.html

Quote
Is that a bug to be fixed in near future

Not likely.

Quote
or will I need to find a different solution by myself?

Follow that thread. There is a fix available, but I'd still avoid the use of String.

Quote
I'm not very used to handling strings using char-arrays or char*s. Is there any good tutorial out there?

Probably. But, it isn't rocket science. Break the problem down into stages. Collect data, and store it in an array. When that works, move onto to parsing/searching the stored data. Keep in mind the need to reset the array and index at appropriate points.

Go Up