Deriving a class constructor with (const char* ) to (const char * PROGMEM)

I'm creating a framework to define a generic implementation of a Nextion display.
All Nextion components defined in their own library are taking a const char* as a constructor parameter, to define the name of the component, used when sending commands to the Nextion (Why not use Pid and Cid??).
The actual runtime objects are created and deleted dynamically when they are active on the display.

As my actual components have a fixed and predefined objectname I would really like to use PROGMEM to store the objectnames. So now I'm trying to define a class with a constructor that takes a PROGMEM char*.

So far I have managed to get to the result below, but that (of course) doesnt work because the original name member is private and const.

I would rather not change the library, but as a last resort, for obvious reasons.

How would you solve this problem?

class A // as defined in library
{
private:
  const char *name;
public:
  A(const char* aName) : name(aName) {}

  String getName() {
    return String(name);
  }
 
};

class B:public A // my own extensions
{
public:
  B(const char* PROGMEM aName) : A("               ") {
    strcpy_P(name, aName);                                           //ERROR because name is private and const in A
  }
};

const char NAME_PROGMEM[] PROGMEM = "name in progmem";

void setup() {
  
  Serial.begin(115200);

  B b(NAME_PROGMEM);
  Serial.println(b.getName()); 
}

void loop() {
}

For Shame!!!

Using pointers in C++!!!

There is no advantage in copying the PROGMEM stuff to a fixed (max) sized RAM buffer,
the compiler uses less memory for his RAM copy of strings.

boolrules:
For Shame!!!

Using pointers in C++!!!

Ehhmm.. sorry but I don't get it..
Probably because I'm not a C/C++ developer in my daytime job

How would you go about programming an Arduino without using pointers?

Object references and/or access methods.

Whandall:
There is no advantage in copying the PROGMEM stuff to a fixed (max) sized RAM buffer,
the compiler uses less memory for his RAM copy of strings.

Bear in mind that classes of type B are created and deleted dynamically (to preserve dynamic m emory), but the possible names are discreet and pre-defined.

Example: The display definition contains 2 pages, page one with 2 buttons ("OK", "CANCEL"), and page 1 with one button "APPLY".
When page 1 is active on the display, I want two instances of MyButton class (derived from NexButton) with the resp names "OK" and "CANCEL", and when page 2 is active the previous buttons are freed from memory and a new instance of MyButton with the name "APPLY" is created.

So I would like to define the names "OK", "CANCEL" and "APPLY" in PROGMEM

boolrules:
Object references and/or access methods.

If I could, I would love to keep with those (being a Java/Delphi programmer during the day) but I don;t think it will do much good for the memory footprint of my sketch

If you are unlucky all the constant " " will be mapped to the same buffer.
You try to write to a constant pointer...

Example: The display definition contains 2 pages, page one with 2 buttons ("OK", "CANCEL"), and page 1 with one button "APPLY".

"OK", "CANCEL", "APPLY" 16 Bytes RAM

"OK ", "CANCEL" // "APPLY " 14 // 7 Bytes RAM

If you need only one long value you may even loose memory, because all buffers have the same max length.

Whandall:
If you are unlucky all the constant " " will be mapped to the same buffer.
You try to write to a constant pointer...

"OK", "CANCEL", "APPLY" 16 Bytes RAM

"OK ", "CANCEL" // "APPLY " 14 // 7 Bytes RAM

If you need only one long value you may even loose memory, because all buffers have the same max length.

Thanks for your reaction.
How would you go about tackling this problem?

class A // as defined in library
{
private:
protected:
  const char *name;
public:
  A(const char* aName) : name(aName) {}

  String getName() {
    return String(name);
  }
 
};

class B:public A // my own extensions
{
public:
  B(const char* PROGMEM aName) : A("               ") {
    strcpy_P(name, aName);                                           //ERROR because name is private and const in A
  }
};

const char NAME_PROGMEM[] PROGMEM = "name in progmem";
const char NAME_PROGMEM1[] PROGMEM = "second name";

void setup() {
 
  Serial.begin(115200);

  B b(NAME_PROGMEM);
  B c(NAME_PROGMEM1);
  Serial.println(b.getName());
  Serial.println(c.getName());
}

void loop() {
}
second name
second name

As you can see, ignoring the warning produces an overwrite.

Somewhere\PROGMEMStringClass\PROGMEMStringClass.ino: In constructor 'B::B(const char*)':
Somewhere\PROGMEMStringClass\PROGMEMStringClass.ino:20:25: warning: invalid conversion from 'const char*' to 'char*' [-fpermissive]
     strcpy_P(name, aName);                                           //ERROR because name is private and const in A
                         ^

The names could only reside in PROGMEM, but that would need some changes to the library.

This works better

class A // as defined in library
{
private:
protected:
  const char *name;
public:
  A(const char* aName) : name(aName) {}
  __FlashStringHelper* getName() {
    return  (__FlashStringHelper*)name;
  }
};

class B:public A // my own extensions
{
public:
  B(const char* PROGMEM aName) : A(aName) { }
};

const char NAME_PROGMEM[] PROGMEM = "name in progmem";
const char NAME_PROGMEM1[] PROGMEM = "second name";

void setup() {
 
  Serial.begin(115200);

  B b(NAME_PROGMEM);
  B c(NAME_PROGMEM1);
  Serial.println(b.getName());
  Serial.println(c.getName());
}

void loop() {
}
name in progmem
second name

...but I don't think it will do much good for the memory footprint of my sketch

You're right. Requirements for garbage collection also limit what you can do on Arduino.
My latest C++ Arduino code used pointers, so I was just having a little fun above.

boolrules:
Requirements for garbage collection also limit what you can do on Arduino.

What requirements? For a non-existent Feature?

You just have to delete all allocated objects yourself and pray that you don't fragment your small memory.

You just have to delete all allocated objects yourself and pray that you don't fragment your small memory.

Yes. That would be garbage collection. That's what I mean.

That is called dynamic memory management.

Garbage collection usualy needs some kind of reference counting to be able to detect garbage.
That feature does not exist in current C++ version.

Jesus.