Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

running into troubles with const member

60 views
Skip to first unread message

stdcerr

unread,
Aug 20, 2019, 12:37:11 AM8/20/19
to
Hi,

I’m running into an issue with a class design (so I believe) so I'm looking for input on how to improve my broken attempt:
Imagine I have a mother class which initializes a QSettings *instance (in the below code the mother is main())that all other classes should use as well. So, I store it as a const private member in my mother class and pass it on to children in their constructors.
Along with the QSettings *instance, there also is a name for each child class which will be used to form a group that stores the respective params
.
I'm running into issues with nme_set(), the compiler says:
foo.cpp: In member function ‘void foo::nme_set(const QString&)’:
foo.cpp:8:46: error: passing ‘const QString’ as ‘this’ argument discards qualifiers [-fpermissive]
void nme_set(const QString &s) {name = s;}
and I'm not exactly sure what to change, can anyone help me?

How about the class design, is this how "you" do it?

Thanks for your time & help! Every effort is much appreciated!


#include <QString>
#include <QSettings>

class foo {
Q_OBJECT
public:
foo(const QSettings *set=nullptr) { if (set) settings = set;}
void nme_set(const QString &s) {name = s;}
QString nme_get() {return name;}
void qux(void);

private:
const QString name;
const QSettings *settings;
};

void foo::qux(void) {
QString name = nme_get();
settings->beginGroup(name);
/*
* ...
*/
settings->endGroup();
}


int main (void) {

const QSettings *sttngs = new QSettings(QSettings::NativeFormat,QSettings::UserScope,"GNU","scaper",nullptr);

foo *inst = foo(sttngs);
inst->nme_set("quux");
inst->qux();

return 0;
}

Ian Collins

unread,
Aug 20, 2019, 12:59:36 AM8/20/19
to

On 20/08/2019 16:36, stdcerr wrote:
> Hi,
>
> I’m running into an issue with a class design (so I believe) so I'm looking for input on how to improve my broken attempt:
> Imagine I have a mother class which initializes a QSettings *instance (in the below code the mother is main())that all other classes should use as well. So, I store it as a const private member in my mother class and pass it on to children in their constructors.
> Along with the QSettings *instance, there also is a name for each child class which will be used to form a group that stores the respective params
> ..
> I'm running into issues with nme_set(), the compiler says:
> foo.cpp: In member function ‘void foo::nme_set(const QString&)’:
> foo.cpp:8:46: error: passing ‘const QString’ as ‘this’ argument discards qualifiers [-fpermissive]
> void nme_set(const QString &s) {name = s;}
> and I'm not exactly sure what to change, can anyone help me?

You have declared name as a const member, so the only place you can set
it is in the constructor. If you don't want it set the name in the
constructor, don't make it const.

> How about the class design, is this how "you" do it?
>
> Thanks for your time & help! Every effort is much appreciated!
>
>
> #include <QString>
> #include <QSettings>
>
> class foo {
> Q_OBJECT
> public:
> foo(const QSettings *set=nullptr) { if (set) settings = set;}

This appears rather convoluted, settings is a const member, so you must
set it in the constructor!

> void nme_set(const QString &s) {name = s;}
> QString nme_get() {return name;}
> void qux(void);
>
> private:
> const QString name;
> const QSettings *settings;
> };

--
Ian.

Sam

unread,
Aug 20, 2019, 6:46:44 AM8/20/19
to
Ian Collins writes:


>> class foo {
>> Q_OBJECT
>> public:
>> foo(const QSettings *set=nullptr) { if (set) settings = set;}
>
> This appears rather convoluted, settings is a const member, so you must set
> it in the constructor!

settings is not a const member.

name is a const member.

>
>> void nme_set(const QString &s) {name = s;}
>> QString nme_get() {return name;}
>> void qux(void);
>> private:
>> const QString name;
>> const QSettings *settings;
>> };

But everything else still applies. name is a const member. It can only be
initialized in the constructor, specifically in the constructor's
initialization section. Since QString has a default constructor, if it is
not explicitly initialized it gets default-constructed.

Either way, name is const and, by definition, 'name=s' will not work.
Because name is const. That's what "const" means.

stdcerr

unread,
Aug 20, 2019, 10:00:01 AM8/20/19
to
Thanks Sam & Ian for your time to reply!

On Tuesday, August 20, 2019 at 3:46:44 AM UTC-7, Sam wrote:
> Ian Collins writes:
>
>
> >> class foo {
> >> Q_OBJECT
> >> public:
> >> foo(const QSettings *set=nullptr) { if (set) settings = set;}
> >
> > This appears rather convoluted, settings is a const member, so you must set
> > it in the constructor!
>
> settings is not a const member.

Oh, I intended it to be one, I guess it should rather be written QSettings * const settings; then

>
> name is a const member.
>
> >
> >> void nme_set(const QString &s) {name = s;}
> >> QString nme_get() {return name;}
> >> void qux(void);
> >> private:
> >> const QString name;
> >> const QSettings *settings;
> >> };
>
> But everything else still applies. name is a const member. It can only be
> initialized in the constructor, specifically in the constructor's
> initialization section. Since QString has a default constructor, if it is
> not explicitly initialized it gets default-constructed.
>
> Either way, name is const and, by definition, 'name=s' will not work.
> Because name is const. That's what "const" means.

Right, this is how I learnt about the initialization list. So I've refactured my code but It still does not compile, it now looks like this:

#include <QString>
#include <QSettings>

class foo {
Q_OBJECT
public:
foo(const QSettings *set=0, const QString s="") : name(s),settings(set){}
QString nme_get() {return name;}
void qux(void);

private:
const QString name;
QSettings * const settings;
};

void foo::qux(void) {
QString name = nme_get();
settings->beginGroup(name);
/*
* ...
*/
settings->endGroup();
}


int main (void) {

const QSettings *sttngs = new QSettings(QSettings::NativeFormat,QSettings::UserScope,"GNU","scaper",0);

foo *inst = foo(sttngs, QString("quux"));
inst->qux();

return 0;
}

and the compiler says:
foo.cpp: In constructor ‘foo::foo(const QSettings*, QString)’:
foo.cpp:7:85: error: invalid conversion from ‘const QSettings*’ to ‘QSettings*’ [-fpermissive]
foo(const QSettings *set=nullptr, const QString s="") : name(s),settings(set){}
^
foo.cpp: In function ‘int main()’:
foo.cpp:31:44: error: cannot convert ‘foo’ to ‘foo*’ in initialization
foo *inst = foo(sttngs, QString("quux"));
^
Makefile:471: recipe for target 'foo.o' failed
make: *** [foo.o] Error 1

Why does it still say "invalid conversion from ‘const QSettings*’ to ‘QSettings*’" and what's wrong with my "foo*", I know I could make this go away by just not declaring insta as a pointer but what's the reason for the complaint?

Thanks!

Szyk Cech

unread,
Aug 20, 2019, 11:21:50 AM8/20/19
to
> #include <QString>
> #include <QSettings>
>
> class foo {
> Q_OBJECT
> public:
> foo(const QSettings *set=0, const QString s="") : name(s),settings(set){}
> QString nme_get() {return name;}
> void qux(void);
>
> private:
> const QString name;

This:

> QSettings * const settings;

Should be:
const QSettings* settings;

Paavo Helde

unread,
Aug 20, 2019, 11:58:50 AM8/20/19
to
On 20.08.2019 18:21, Szyk Cech wrote:
>> #include <QString>
>> #include <QSettings>
>>
>> class foo {
>> Q_OBJECT
>> public:
>> foo(const QSettings *set=0, const QString s="") :
>> name(s),settings(set){}
>> QString nme_get() {return name;}
>> void qux(void);
>> private:
>> const QString name;
>
> This:
>
>> QSettings * const settings;
>
> Should be:
> const QSettings* settings;
>

This he already had earlier. Maybe he wants

const QSettings* const settings;


stdcerr

unread,
Aug 20, 2019, 1:44:42 PM8/20/19
to
On Tuesday, August 20, 2019 at 8:58:50 AM UTC-7, Paavo Helde wrote:
> On 20.08.2019 18:21, Szyk Cech wrote:
> >> #include <QString>
> >> #include <QSettings>
> >>
> >> class foo {
> >> Q_OBJECT
> >> public:
> >> foo(const QSettings *set=0, const QString s="") :
> >> name(s),settings(set){}
> >> QString nme_get() {return name;}
> >> void qux(void);
> >> private:
> >> const QString name;
> >
> > This:
> >
> >> QSettings * const settings;
> >
> > Should be:
> > const QSettings* settings;
> >
>
> This he already had earlier.

yes, Thanks!

> Maybe he wants
>
> const QSettings* const settings;

I want a cost pointer to QSettings. Originally, I thought const QSettings* settings would give me that until Sam told me that this is not right but why notI'm not exactly sure.

Paavo Helde

unread,
Aug 20, 2019, 2:20:00 PM8/20/19
to
A const pointer to mutable QSettings is 'QSettings * const'. If you want
this, you need to use the same type also in the constructor, not 'const
QSettings *' you have above.

Sam

unread,
Aug 20, 2019, 8:07:52 PM8/20/19
to
stdcerr writes:


> Right, this is how I learnt about the initialization list. So I've
> refactured my code but It still does not compile, it now looks like this:
>
> #include <QString>
> #include <QSettings>
>
> class foo {
> Q_OBJECT
> public:
> foo(const QSettings *set=0, const QString s="") :
> name(s),settings(set){}

You must be using an obsolete C++ book. Modern C++ uses uniform
initialization syntax, which would be:

foo(const QSettings *set=0, const QString s="") : name{s},settings{set}{}

Basically {} instead of (). This resolves some syntax ambiguities in other
situations (not this particular one, but others, and it's better to remain
consistent).

> QSettings * const settings;

settings is now a const class member that's a pointer to a non-const
QSettings object.

const QSettings *set=nullptr, const QString s="") :
> name(s),settings(set){}
>
> ^
> foo.cpp: In function ‘int main()’:
> foo.cpp:31:44: error: cannot convert ‘foo’ to ‘foo*’ in initialization
> foo *inst = foo(sttngs, QString("quux"));
> ^
> Makefile:471: recipe for target 'foo.o' failed
> make: *** [foo.o] Error 1
>
> Why does it still say "invalid conversion from ‘const QSettings*’ to
> ‘QSettings*’"

Because your parameter to the constructor is a 'const QSettings *', and your
const class member is a pointer to a non-const QSettings.

These are two different things: the pointer, and what it points to. Either
one, or both, can be const.

So, either your parameter to the constructor should be

QSettings *set=nullptr

or your class member should be

const QSettings * const settings;

Which is a const class member named "settings" which is a pointer to a const
QSettings object.

stdcerr

unread,
Aug 20, 2019, 10:10:17 PM8/20/19
to
DUH! That seems obvious! Thanks!

red floyd

unread,
Aug 21, 2019, 1:19:48 PM8/21/19
to
Easiest way to check is to read the declaration from RIGHT TO LEFT.

Thus,

const QSettings *x = x is a pointer to a const QSettings
QSettings * const x = x is a const pointer to QSettings

This is why some people write:

int const x = 7; // x is a const int

Message has been deleted

James Kuyper

unread,
Aug 21, 2019, 11:52:17 PM8/21/19
to
On 8/21/19 11:12 PM, stdcerr wrote:
> On Tuesday, August 20, 2019 at 5:07:52 PM UTC-7, Sam wrote:
>> stdcerr writes:
>>
>>
>>> Right, this is how I learnt about the initialization list. So I've
>>> refactured my code but It still does not compile, it now looks like this:
>>>
>>> #include <QString>
>>> #include <QSettings>
>>>
>>> class foo {
>>> Q_OBJECT
>>> public:
>>> foo(const QSettings *set=0, const QString s="") :
>>> name(s),settings(set){}
...
>>> foo.cpp: In function ‘int main()’:
>>> foo.cpp:31:44: error: cannot convert ‘foo’ to ‘foo*’ in initialization
>>> foo *inst = foo(sttngs, QString("quux"));
>>> ^
>>> Makefile:471: recipe for target 'foo.o' failed
>>> make: *** [foo.o] Error 1
>
> I'm not sure why the compiler doesn't like is, why can't the instance of foo not be a pointer? ...

An instance of foo has class type. An class type is, by definition, not
a pointer type. You could have defined an implicit conversion from an
object of type foo to a pointer to a foo object, but that's almost
certainly not what you wanted.

> ... To get past this, I changed it to look like:
> foo inst = foo(sttngs, QString("quux"));

Note: the line above is equivalent to
foo inst(sttngs, QString("quux"));

> inst.qux();...
>>> Why does it still say "invalid conversion from ‘const QSettings*’ to
>>> ‘QSettings*’"
>>
>> Because your parameter to the constructor is a 'const QSettings *', and your
>> const class member is a pointer to a non-const QSettings.
>>
>> These are two different things: the pointer, and what it points to. Either
>> one, or both, can be const.
>>
>> So, either your parameter to the constructor should be
>>
>> QSettings *set=nullptr
>>
>> or your class member should be
>>
>> const QSettings * const settings;
>>
>> Which is a const class member named "settings" which is a pointer to a const
>> QSettings object.

Let me review your options:

const QSettings * const settings;
Declares settings to be a pointer, which cannot be changed, to a
QSettings object that cannot be changed through that pointer.

QSettings * const settings;
Declares settings to be a pointer, which cannot be changed, to a
QSettings object that can be changed through that pointer.

const QSettings * settings;
Declares settings to be a pointer, which can be changed, to a QSettings
object that cannot be changed through that pointer.

QSettings * settings;
Declares settings to be a pointer, which can be changed, to a QSettings
object that can be changed through that pointer.

So, which of these declarations is most appropriate for your
application? Your code never changes the value of settings once it has
been initialized, so declaring settings itself const makes sense.

However:

...
> foo.cpp: In member function ‘void foo::qux()’:
> foo.cpp:18:30: error: passing ‘const QSettings’ as ‘this’ argument discards qualifiers [-fpermissive]
> settings->beginGroup(name);

<https://doc.qt.io/qt-5/qsettings.html#beginGroup> does not include the
'const' keyword in the declaration for beginGroup(), which is easy to
understand, since it describes the behavior as "Appends prefix to the
current group.", an action that requires modification of the QSettings
object.

Therefore, since you call settings->beginGroup(), it does NOT make sense
to declare "settings" as a pointer that cannot be used to modify the
object it points at. What you want is

QSetting * const settings;

> Does this mean beginGroup() and endGroup() cannot be invoked on a const QSettings pointer ?

Yes.

stdcerr

unread,
Aug 21, 2019, 11:55:34 PM8/21/19
to
On Tuesday, August 20, 2019 at 5:07:52 PM UTC-7, Sam wrote:
> stdcerr writes:
>
>
> > Right, this is how I learnt about the initialization list. So I've
> > refactured my code but It still does not compile, it now looks like this:
> >
> > #include <QString>
> > #include <QSettings>
> >
> > class foo {
> > Q_OBJECT
> > public:
> > foo(const QSettings *set=0, const QString s="") :
> > name(s),settings(set){}
>
> You must be using an obsolete C++ book.

I'm mostly using the Internet to find out things now, I've been writing C for many years and know a little about C++(obviously not much/enough) - any good book you would recommend?

Modern C++ uses uniform
> initialization syntax, which would be:
>
> foo(const QSettings *set=0, const QString s="") : name{s},settings{set}{}
>
> Basically {} instead of (). This resolves some syntax ambiguities in other
> situations (not this particular one, but others, and it's better to remain
> consistent).

Okay, looks a bit like Lambda in C++11...
Yes, I'm all for consistency, too! Thanks!
>
> > QSettings * const settings;
>
> settings is now a const class member that's a pointer to a non-const
> QSettings object.
>
> const QSettings *set=nullptr, const QString s="") :
> > name(s),settings(set){}
> >
> > ^
> > foo.cpp: In function ‘int main()’:
> > foo.cpp:31:44: error: cannot convert ‘foo’ to ‘foo*’ in initialization
> > foo *inst = foo(sttngs, QString("quux"));
> > ^
> > Makefile:471: recipe for target 'foo.o' failed
> > make: *** [foo.o] Error 1
> >
> > Why does it still say "invalid conversion from ‘const QSettings*’ to
> > ‘QSettings*’"
>
> Because your parameter to the constructor is a 'const QSettings *', and your
> const class member is a pointer to a non-const QSettings.

DUH! Yep, obviously needs to be the same!

>
> These are two different things: the pointer, and what it points to. Either
> one, or both, can be const.
>
> So, either your parameter to the constructor should be
>
> QSettings *set=nullptr
>
> or your class member should be
>
> const QSettings * const settings;
>
> Which is a const class member named "settings" which is a pointer to a const
> QSettings object.

Okay, I guess I want a const pointer to a const Object, hence I'll go with:

const QSettings * const settings;

But I still have issues, my code now looks like:

class foo {
Q_OBJECT
public:
foo(const QSettings* const set=nullptr, const QString s="") : name{s},settings{set}{}
QString nme_get() {return name;}
void qux(void);

private:
const QString name;
const QSettings * const settings;
};

void foo::qux(void) {
QSettings *test = settings;
QString name = nme_get();
test->beginGroup(name);
/*
* ...
*/
test->endGroup();
}


int main (void) {

const QSettings *sttngs = new QSettings(QSettings::NativeFormat,QSettings::UserScope,"GNU","scaper",nullptr
);

foo inst = foo(sttngs, QString("quux"));
inst.qux();

return 0;
}

but g++ still tells me:
foo.cpp: In member function ‘void foo::qux()’:
foo.cpp:17:23: error: invalid conversion from ‘const QSettings*’ to ‘QSettings*’ [-fpermissive]
QSettings *test = settings;

Sam

unread,
Aug 22, 2019, 8:40:37 AM8/22/19
to
stdcerr writes:

>
> I'm mostly using the Internet to find out things now, I've been writing C
> for many years and know a little about C++(obviously not much/enough) - any
> good book you would recommend?

There's a good list here:

https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list

> but g++ still tells me:
> foo.cpp: In member function ‘void foo::qux()’:
> foo.cpp:17:23: error: invalid conversion from ‘const QSettings*’ to
> ‘QSettings*’ [-fpermissive]
> QSettings *test = settings;
> ^
> Makefile:471: recipe for target 'foo.o' failed
> make: *** [foo.o] Error 1

It is true that C++ compilers have a rich reputation for incomprehensible,
undecipherable error messages, but this is not one of them, it's as clear as
it can be.

Of course, you do need to already understand some C++ fundamentals, such as
what it means to be a const, and that a pointer to const cannot be converted
to a pointer to a non-const object, which is what the error message states.

settings is a "const QSettings *", a pointer to a constant QSettings object.
You are trying to assign it to a pointer to "QSettings *". That's it. No big
mystery. Verbotten. Nyet. Nada. No way. Nein. You /can/ assign a "QSetting
*" to a "const QSetting *", basically promising to never modify anything
that the "const QSetting *" points to. But once you made that promise it's a
one way street. It's true that you might still have the original "QSettings
*" somewhere. But as far as the promise made about the new "const QSettings
*", it is etched in stone, and irrevocable. So that means that you can't
make a "QSettings *" out of it, again.

Perhaps you want to grab one of those C++ books, which should explain all of
this, and all the rest of your compilation errors will suddenly make sense
to me. That might be a more efficient way to get this done.


Jorgen Grahn

unread,
Aug 22, 2019, 10:44:57 AM8/22/19
to
On Thu, 2019-08-22, stdcerr wrote:
> On Tuesday, August 20, 2019 at 5:07:52 PM UTC-7, Sam wrote:
...
>> You must be using an obsolete C++ book.
>
> I'm mostly using the Internet to find out things now, I've been
> writing C for many years and know a little about C++(obviously not
> much/enough) - any good book you would recommend?

I think you do need a book, for the bigger picture at least.

Stroustrup: The C++ Programming Language. The edition that covers
C++11.

Disclaimers:
- Don't know if there's a C++17 edition or whatever on the way.
I use the C++11 book and use online sources for the relatively
smaller changes after 2011. For the standard library details I
almost always go online.
- Other recent books may be good.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

stdcerr

unread,
Aug 26, 2019, 10:31:12 PM8/26/19
to
On Thursday, August 22, 2019 at 7:44:57 AM UTC-7, Jorgen Grahn wrote:
> On Thu, 2019-08-22, stdcerr wrote:
> > On Tuesday, August 20, 2019 at 5:07:52 PM UTC-7, Sam wrote:
> ...
> >> You must be using an obsolete C++ book.
> >
> > I'm mostly using the Internet to find out things now, I've been
> > writing C for many years and know a little about C++(obviously not
> > much/enough) - any good book you would recommend?
>
> I think you do need a book, for the bigger picture at least.
>
> Stroustrup: The C++ Programming Language. The edition that covers
> C++11.

I used the Stroustrup book back in the 90ties too. It's a good piece! And yes, i I will pickup a newer version of it at some point! Thank you!
0 new messages