From: Daniel Krügler on
On 18 Apr., 03:33, t.wa...(a)nci-sw.com wrote:
> I'm trying to slowly convert some C code to C++ and have encounter
> what's probably a trivial problem.
>
> The easiest way to describe the problem is with an example:
>
> class FOO
> {
> public:
> int Version(void){return m_ver;};

Version is a member function without const qualifier.
Thus you cannot invoke this function on a const object
or on a reference or pointer to const Version.
Additionally, while formally correct, most programmers
would remove the void parameter from above parameter
list, because in C++ it does not add anything useful
to the function signature. Note also that the final semicolon
is optional here.
To solve your problem, you want to change the signature
of this function to

int Version(void) const {return m_ver;};

or to

int Version() const {return m_ver;}

> FOO(){m_ver = 1;};
> private:
> int m_ver;
> };
>
> void PrintVer(const FOO * fp)
> {
> int v = fp->Version(); /* error here */
>
> cout << "The version is " << v << endl;
> }

Given above modification this should compile now.
Considering that PrintVer could not work reasonably
with a NULL pointer argument, you could consider to
modify the definition of PrintVer as well using references
instead:

void PrintVer(const FOO& fp)
{
int v = fp.Version();
//...
}

> If I remove the const from the routine declaration, it works fine, but
> I'd rather not do that. I guess I don't understand what the compiler
> is trying to tell me, and have no idea of how to work around this
> without removing the const.

If you add the const qualifier as shown above, you are promising
that PrintVer will not modify any data member directly and that
you can only invoke any member function with const qualifier
or free function with pointers/references to const. It's easier to
understand this constraint, if you would assume for a while that
your *original* Version would not be a member function, but a free
or static member function, like this

int Version(FOO& arg){return arg.m_ver;}

ignoring here that such free function could usually not access the
m_ver data member.
Now consider your function PrintVer function, which would invoke
this function:

void PrintVer(const FOO& fp)
{
int v = Version(fp);
//...
}

If the compiler would allow this, then it would be very easy to
break the const guarantee that PrintVer has given, because
PrintVer says "I do not allow modifications". This is so, because
given the non-const signature (either as member function or as
free or static member function) you could similarly write

int Version(FOO& arg){return ++arg.m_ver;}

but if you declare Version as

int Version(const FOO& arg){return ++arg.m_ver;}

the compiler would reject this code immediately.

In short: A const-qualified member function behaves like
a normal function, where you have added one further argument
of reference to const class type. In fact, most - if not all -
compilers will represent non-static member functions in
that or a similar way.

Last but not least: The same reasoning applies to the volatile-
qualifier or any cv-combination as well.

HTH & Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thomas J. Gritzan on
t.wanat(a)nci-sw.com schrieb:
> I'm trying to slowly convert some C code to C++ and have encounter
> what's probably a trivial problem.
>
> The easiest way to describe the problem is with an example:
>
> class FOO

All uppercase names are reserved for macros. So you should rename it to Foo.

> {
> public:
> int Version(void){return m_ver;};

Make this a const member function. That will fix the problem.

Empty parameter lists usually are written as () in C++, while as (void) in C.

int Version() const { return m_ver; }

> FOO(){m_ver = 1;};

Prefer initialization lists to assignment in constructors:

F() : m_ver(1) {}

> private:
> int m_ver;
> };
>
> void PrintVer(const FOO * fp)

In C++, you prefer references to pointers:

void PrintVar(const FOO& foo)

> {
> int v = fp->Version(); /* error here */
>
> cout << "The version is " << v << endl;
> }
>
> When I try to compile, I get the error
> 'FOO::Version' cannot convert 'this' pointer from 'const FOO' to 'FOO
> &'
>
> on the line containing fp->Version().
>
> If I remove the const from the routine declaration, it works fine, but
> I'd rather not do that. I guess I don't understand what the compiler
> is trying to tell me, and have no idea of how to work around this
> without removing the const.

--
Thomas
http://www.netmeister.org/news/learn2quote.html
:wq

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Lionel B on
On Thu, 17 Apr 2008 19:33:58 -0600, t.wanat wrote:

> I'm trying to slowly convert some C code to C++ and have encounter
> what's probably a trivial problem.
>
> The easiest way to describe the problem is with an example:
>
> class FOO
> {
> public:
> int Version(void){return m_ver;};
// ^ ^
// drop the "void" extraneous ";"

int Version() const {return m_ver;}
// ^
// add this

> FOO(){m_ver = 1;};
// ^
// extraneous ";"
> private:
> int m_ver;
> };
>
> void PrintVer(const FOO * fp)
> {
> int v = fp->Version(); /* error here */
>
> cout << "The version is " << v << endl; }
>
> When I try to compile, I get the error 'FOO::Version' cannot convert
> 'this' pointer from 'const FOO' to 'FOO &'
>
> on the line containing fp->Version().

This is because "const FOO * fp" declares a pointer to a const FOO
object; so *fp cannot be modified in the function PrintVer(). But the
function FOO::Version() does not guarantee that the FOO object it is
invoked on will not be modified, so the compiler complains. You can
guarantee that FOO::Version() will not modify its invoking object by
declaring it "const" (see above).

Note that declaring the parameter to PrintVer() as "FOO* const fp" would
also solve your problem; it says that the *pointer* fp is const (rather
than the object it points to). It depends what you want, really... if the
function FOO::Version() really does not modify its invoking object it
should be declared const; and if PrintVer() does not modify the pointer
fp *or* the object it points to (as I suspect is your case), then the
parameter should probably be declared as "const FOO* const fp".

> If I remove the const from the routine declaration, it works fine, but
> I'd rather not do that. I guess I don't understand what the compiler
> is trying to tell me, and have no idea of how to work around this
> without removing the const.

Hope this helps,

--
Lionel B

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Gerhard Menzl on
t.wanat(a)nci-sw.com wrote:

> class FOO
> {
> public:
> int Version(void){return m_ver;};
> FOO(){m_ver = 1;};
> private:
> int m_ver;
> };
>
> void PrintVer(const FOO * fp)
> {
> int v = fp->Version(); /* error here */
>
> cout << "The version is " << v << endl;
> }
>
> When I try to compile, I get the error
> 'FOO::Version' cannot convert 'this' pointer from 'const FOO' to 'FOO
> &'
>
> on the line containing fp->Version().
>
> If I remove the const from the routine declaration, it works fine, but
> I'd rather not do that. I guess I don't understand what the compiler
> is trying to tell me, and have no idea of how to work around this
> without removing the const.

When you have a pointer to a const object, you can only call const
member functions via this pointer. Your compiler is trying to tell you
that FOO:Version should be changed to:

int Version() const { return m_ver; }

(the void is a C-ism and unnecessary). Version() does not change the
state of FOO, hence it should be const.

As an aside, all-caps identifiers should be reserved for preprocessor
macros if you want to avoid name clashes.

--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thomas Lehmann on
> class FOO
> {
> public:
> int Version(void){return m_ver;};
> FOO(){m_ver = 1;};
> private:
> int m_ver;
> };
>
> void PrintVer(const FOO * fp)

Defining a parameter as const usually results by the
decision not to change the content of that parameter.
Calling 'Version' the none const method can change the
content of FOO and that's why the compiler yells.
Change (a) 'int Version()' to 'int Version() const' or
(b) remove the const from the parameter in 'PrintVer'.
I would prefer the first variant.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]