[comp.lang.c++] const member functions ?

jima@hplsla.HP.COM (Jim Adcock) (07/18/89)

Is there a way to declare a member function const -- IE to tell the compiler
that the member function does not change the value of this nor *this

???

ark@alice.UUCP (Andrew Koenig) (07/18/89)

In article <6590205@hplsla.HP.COM>, jima@hplsla.HP.COM (Jim Adcock) writes:

> Is there a way to declare a member function const -- IE to tell the compiler
> that the member function does not change the value of this nor *this

Yes [in 2.0]:

	class foo {
		int n;
	public:
		void setsize(int k) { n = k; }
		int getsize() const { return n; }
	};

If you say `const' in the declaration, and the definition isn't
in the same place, you must also say `const' in the definition:

	class bar {
		int n;
	public:
		void setsize(int);
		int getsize() const;
	};

	void bar::setsize(int k) { n = k; }
	void foo::getsize() const { return n; }

In a member function defined with `const' this way, `this' is
a pointer to a constant object.

It is meaningless to say `const' for a constructor or destructor:
they can operate on constants anyway.
-- 
				--Andrew Koenig
				  ark@europa.att.com

mhyman@hsfmsh.UUCP (Marco S. Hyman) (07/18/89)

In article <6590205@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
> Is there a way to declare a member function const -- IE to tell the compiler
> that the member function does not change the value of this nor *this
> 
> ???

Release 2.0 supports the following: (according to Lippman's book)

	class x {
		...
	type	func() const {...};
	}

I don't know if it's supported in G++ as I haven't tried it yet.

--marc
-- 
//Marco S. Hyman
//UUCP:   ...!sun!sfsun!hsfmsh!mhyman
//Domain: sfsun!hsfmsh!mhyman@sun.com

daniel@avsd.UUCP (Daniel Edelson) (07/19/89)

>In article <6590205@hplsla.HP.COM>, jima@hplsla.HP.COM (Jim Adcock) writes:
>
>> Is there a way to declare a member function const -- IE to tell the compiler
>> that the member function does not change the value of this nor *this

In article <9633@alice.UUCP> ark@alice.UUCP (Andrew Koenig) responds:
>
>Yes [in 2.0]:
>
>	class foo {
>		int n;
>	public:
>		void setsize(int k) { n = k; }
>		int getsize() const { return n; }
>	};
>
>In a member function defined with `const' this way, `this' is
>a pointer to a constant object.
>-- 
>				--Andrew Koenig
>				  ark@europa.att.com


Why is this feature useful? Is it to improve code readability
by making it clear when a member function does not alter any 
member data? Is there also a reliability motivation?
RE: jima's other question, is there also a syntax for specifying 
that `this' is a constant pointer rather than a pointer to a 
constant object?

How about this?

struct S {
	int x;
	void cmf() const;
};

void put(S *p) { cin >> p->x; }
void look(const S *p) { cout << p->x; }

void S::cmf() const
{
    put(this);  // illegal, put() takes a "S *" but `this' is a "const S *"
    look(this); // legal, look() takes a "const S *", which `this' is
    this=this;  // legal, `this' is of type "const S *", not "S *const"
}

Is this correct?

Daniel Edelson
Currently:  daniel@avsd.UUCP        (Ampex Corporation, Redwood City, CA)
And also:	daniel@saturn.ucsc.edu  (Univ. of Calif., Santa Cruz)

jima@hplsla.HP.COM (Jim Adcock) (07/20/89)

>Why is this feature useful? Is it to improve code 
>readability by making it clear when a member function does not alter any 
>member data? 

yes.

>Is there also a reliability motivation?

yes.  A compiler can check that the const is not violated.  Also, if one
tried to pass by reference a const object to a non-const function, a 
compiler may generate a copy of that const object so that the non-const
function can't molest it.  This keeps FORTRAN-like problems from happening
where that constant 2 you passed by reference gets changed by the routine
to actually be 5.

More importantly, using const in all the right places now lets me get rid
of most of those annoying warning messages when I run +w :-)

ark@alice.UUCP (Andrew Koenig) (08/15/89)

In article <1771@avsd.UUCP>, daniel@avsd.UUCP (Daniel Edelson) writes:

> Why is this feature useful? Is it to improve code readability
> by making it clear when a member function does not alter any 
> member data? Is there also a reliability motivation?

The motivation is to give `const' consistent semantics.

For example:

	class Foo {
	private:
		int x;
	public:
		Foo() { x = 0; }
		void set(int n) { x = n; }
		int get() { return x; }
	};

	void f()
	{
		const Foo a;
		int n = a.get();	// legal
		a.set(7);		// legal or not?
	}

If `const' is to mean anything useful for class objects, there must
be some notion of whether or not calling a member function changes
the object.  Here, Foo::set() changes the object but Foo::get()
doesn't.

Because Foo::set() changes the object, you'd like the line marked
`legal or not?' to be flagged as an error.  But that's impossible
in general because the definitions of Foo::set() and Foo::get()
might have been separately compiled.

Therefore C++2.0 lets you say this:

	class Foo {
	private:
		int x;
	public:
		Foo() { x = 0; }
		void set(int n) { x = n; }
		int get() const { return x; }
	};

The `const' in the definition of Foo::get() says that it's OK to
call Foo::get() on a constant object.  Therefore,

	{
		const Foo a;
		int n = a.get();	// legal
		a.set(7);		// illegal
	}

The line marked `illegal' is illegal because `a' is a const object
and Foo::set() can't be called for a constant.

> RE: jima's other question, is there also a syntax for specifying 
> that `this' is a constant pointer rather than a pointer to a 
> constant object?

There's no syntax for saying that `this' is a constant pointer.
However, assignment to `this' is deprecated; some future version
of C++ will uniformly treat `this' as a constant pointer.

> How about this?

> struct S {
> 	int x;
> 	void cmf() const;
> };

OK so far, S::cmf is a member that can be called on a const object.

> void put(S *p) { cin >> p->x; }
> void look(const S *p) { cout << p->x; }

No problems here.

> void S::cmf() const
> {
>     put(this);  // illegal, put() takes a "S *" but `this' is a "const S *"
>     look(this); // legal, look() takes a "const S *", which `this' is
>     this=this;  // legal, `this' is of type "const S *", not "S *const"
> }

Right you are.  I'll reiterate, though, that saying `this=this'
is a dangerous anachronism and should be avoided and ultimately
eliminated.  In fact, I'm not sure what purpose it serves if it's
not in a constructor or destructor.
-- 
				--Andrew Koenig
				  ark@europa.att.com