user45247: I have a class which has a const char * property:
    class A
    {
    public:
        const PROGMEM char* text;
    };

    void setup()
    {
        // A a{"Hello World!"};
        // A a{PSTR("Hello World!")};

        A a;
        a.text = PSTR("Hello World!");

        Serial.begin(9600);
        delay(30);
        Serial.println(a.text);
    }

    void loop()
    {
    }

I’d like to spare some RAM using PROGMEM.
How to initialize a object then?
Obviously, it can’t be like this:
    A a{PSTR("Hello World!")};

This will do:
    A a;
    a.text = PSTR("Hello World!");

However, I need to pass string to the constructor.

user7508: It is a shame that gcc only supports the __flash qualifier in C mode,
not in C++, so we have to use PROGMEM instead. Unlike __flash, which
qualifies a variable just like const, the PROGMEM attribute only has
effect when allocating room for a variable. Once the allocation is done,
the compiler forgets about the attribute. In particular, a declaration
such as
const PROGMEM char* text;

does not allocate flash space, so it generates the warning
warning: ‘__progmem__’ attribute ignored [-Wattributes]
     const PROGMEM char* text;
                         ^

You can thus forget the attribute when declaring a pointer, as there is
no such thing as a “pointer to PROGMEM”. You just use a const char *
instead.
Now, the second issue is that, as far as Serial.println() is
concerned, the pointer above is a plain const char *, so it will
interpret it as an address in RAM, and print garbage. If you want
Serial.println() to know you are giving it an address in flash, you
should provide it with a const __FlashStringHelper* pointer.
Here is the solution I propose. Tested on an Uno-compatible board:
class A
{
public:
    A(const char* s)
        : text(reinterpret_cast<const __FlashStringHelper *>(s)) {}
    const __FlashStringHelper* text;
};

void setup()
{
    A a{PSTR("Hello World!")};
    Serial.begin(9600);
    Serial.println(a.text);
}

void loop(){}


Edit: After seeing the last version of Juraj’s answer, I must say
that I agree with him. Since we are using the Arduino API, it makes more
sense for the constructor to take a const __FlashStringHelper*, and
for the caller to use the F() macro.

user37622: const char* text; is a pointer to constant not a constant pointer (char * const text is a constant pointer). So you can assign a pointer to a constant char array to const char* text; even a pointer to an array in PROGMEM. 
The compiler doesn't know the difference between a PROGMEM pointer and a pointer in SRAM. It is on you to work in code with a pointer to PROGMEM the right way.
so remove PROGMEM from const PROGMEM char* text;

add constructor to initialize an object.
A(const char* _text) {
  text = _text;
}

and then
A a(PSTR("Hello World!"));


EDIT:
you could use Arduino's F() macro and __FlashStringHelper type, because it is supported by Serial print and co.
class A
{
public:
  A(const __FlashStringHelper* _text) {
    text = _text;
  }
  const __FlashStringHelper* text;
};

void setup()
{
    A a(F("Hello World!"));

    Serial.begin(9600);
    delay(30);
    Serial.println(a.text);
}

void loop()
{
}

__FlashStringHelper type is trick to distinguish PROGMEM strings from char arrays in SRAM..

45247: <p>I have a class which has a <code>const char *</code> property:</p>

<pre class="lang-cpp prettyprint-override"><code>    class A
    {
    public:
        const PROGMEM char* text;
    };

    void setup()
    {
        // A a{"Hello World!"};
        // A a{PSTR("Hello World!")};

        A a;
        a.text = PSTR("Hello World!");

        Serial.begin(9600);
        delay(30);
        Serial.println(a.text);
    }

    void loop()
    {
    }
</code></pre>

<p>I’d like to spare some RAM using <code>PROGMEM</code>.</p>

<p>How to initialize <code>a</code> object then?</p>

<p>Obviously, it can’t be like this:</p>

<pre class="lang-cpp prettyprint-override"><code>    A a{PSTR("Hello World!")};
</code></pre>

<p>This will do:</p>

<pre class="lang-cpp prettyprint-override"><code>    A a;
    a.text = PSTR("Hello World!");
</code></pre>

<p>However, I need to pass string to the constructor.</p>
 7508: <p>It is a shame that gcc only supports the <code>__flash</code> qualifier in C mode,
not in C++, so we have to use <code>PROGMEM</code> instead. Unlike <code>__flash</code>, which
qualifies a variable just like <code>const</code>, the <code>PROGMEM</code> attribute only has
effect when allocating room for a variable. Once the allocation is done,
the compiler forgets about the attribute. In particular, a declaration
such as</p>

<pre class="lang-cpp prettyprint-override"><code>const PROGMEM char* text;
</code></pre>

<p>does not allocate flash space, so it generates the warning</p>

<pre><code>warning: ‘__progmem__’ attribute ignored [-Wattributes]
     const PROGMEM char* text;
                         ^
</code></pre>

<p>You can thus forget the attribute when declaring a pointer, as there is
no such thing as a “pointer to <code>PROGMEM</code>”. You just use a <code>const char *</code>
instead.</p>

<p>Now, the second issue is that, as far as <code>Serial.println()</code> is
concerned, the pointer above is a plain <code>const char *</code>, so it will
interpret it as an address in RAM, and print garbage. If you want
<code>Serial.println()</code> to know you are giving it an address in flash, you
should provide it with a <code>const __FlashStringHelper*</code> pointer.</p>

<p>Here is the solution I propose. Tested on an Uno-compatible board:</p>

<pre class="lang-cpp prettyprint-override"><code>class A
{
public:
    A(const char* s)
        : text(reinterpret_cast&lt;const __FlashStringHelper *&gt;(s)) {}
    const __FlashStringHelper* text;
};

void setup()
{
    A a{PSTR("Hello World!")};
    Serial.begin(9600);
    Serial.println(a.text);
}

void loop(){}
</code></pre>

<hr>

<p><strong>Edit</strong>: After seeing the last version of Juraj’s answer, I must say
that I agree with him. Since we are using the Arduino API, it makes more
sense for the constructor to take a <code>const __FlashStringHelper*</code>, and
for the caller to use the <code>F()</code> macro.</p>
 37622: <p><code>const char* text;</code> is a pointer to constant not a constant pointer (<code>char * const text</code> is a constant pointer). So you can assign a pointer to a constant char array to <code>const char* text;</code> even a pointer to an array in PROGMEM. </p>

<p>The compiler doesn't know the difference between a PROGMEM pointer and a pointer in SRAM. It is on you to work in code with a pointer to PROGMEM the right way.</p>

<p>so remove PROGMEM from <code>const PROGMEM char* text;</code></p>

<hr>

<p>add constructor to initialize an object.</p>

<pre><code>A(const char* _text) {
  text = _text;
}
</code></pre>

<p>and then</p>

<pre><code>A a(PSTR("Hello World!"));
</code></pre>

<hr>

<p>EDIT:</p>

<p>you could use Arduino's F() macro and __FlashStringHelper type, because it is supported by Serial print and co.</p>

<pre><code>class A
{
public:
  A(const __FlashStringHelper* _text) {
    text = _text;
  }
  const __FlashStringHelper* text;
};

void setup()
{
    A a(F("Hello World!"));

    Serial.begin(9600);
    delay(30);
    Serial.println(a.text);
}

void loop()
{
}
</code></pre>

<p>__FlashStringHelper type is trick to distinguish PROGMEM strings from char arrays in SRAM..</p>
