Const Class Qualifier

Pages: 12
I am not able to understand what "const class" qualifier stands for in the following declaration

1
2
3
4
	A(const class B& a)
	{
		std::cout<<"class B is converted to A";
	}



My next question is based on the following code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class A
{
public:
	A(const class B& a)
	{
		std::cout<<"class B is converted to A";
	}
};

class B
{
	int c;
public:
	void get() const
	{
		c=10;
	}
};

void function(const A& a)
{
	std::cout<<"Value of a is " <<c1.getA();
}


int main(int argc, char* argv[])
{ 
        B b;    // line 1
	function(b); //line 2
	
}



line 2 only works if the constructor for class A is A(const class B& a) and ofcourse the function definition is void function(const A& a)

I am not able to understand the chain of events happening here. Can anyone of you explain?
When you define a constructor with only one parameter, which is the reference or value of a different class-object, you tell the compiler that implicit conversions are possible. This means that B can be A. (While A cannot necessarily be B, in this code.) Since the function calls a member function which is local to A, it cannot have const B& as parameter. But, because of the possibility to read B as A, B is allowed to be put into that function.
Last edited on
@Kylon.. Thanks.. What I am not able to understand is that why the A(B& a) is not able to the job that A(const class B& a) does? why does compiler throw error during compilationf for my former declaration?
karthick88 wrote:
What I am not able to understand is that why the A(B& a) is not able to the job that A(const class B& a) does?

It's because the compiler doesn't know that B is the name of a class. This will work:

1
2
3
4
5
6
7
8
9
10
11
12
class B; //<- forward declaration

class A
{
public:
    A(const B& a)
    {
        std::cout<<"class B is converted to A";
    }
};

class B {/*...*/};
Eventhen why is there a stress on const? why not A(B& a) {..}?

The idea behind const objects is that they can't be changed.

To ensure this, there are a few rules:

- const objects can only have const functions called on them
- const objects can only be passed as const parameters
- const functions cannot change the state of 'this'


Consider the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class B
{
public:
  int foo;
};

class A
{
public:
  A(B& b)
  {
    b.foo = 5;  // since b is not const, this is perfectly acceptable
  }
};


int main()
{
  const B b;  // a const B object
  // the whole point of the const keyword is to guarantee 'b's state won't change.  It is constant.

  A a(b);  // ERROR
}


This is an error because 'b' is const, and the A ctor would be changing it (destroying its const-ness).
@ Kyon
This means that B can be A
that's a problematic statement. A can take a copy of what ever B contains (at that time A knows B of course). but A never behaves like B

@ karthick88
as long as A don't know anything about B A is not able to access anything of B no matter if you write 'const B&' or 'B&'.
I was more or less stating the same as you just did. The lower level fallacies seemed redundant and would over complicate things a lot. Also, +1 to forward declaration.
@coder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

class B;

class A
{
public:
	A(const class B& a)
	{
		std::cout<<"class B is converted to A";
	}
};

class B
{
	int c;
public:
	void get() const
	{
		c=10;
	}
};

void function(A& a)
{
	std::cout<<"Value of a is " <<c1.getA();
}


int main(int argc, char* argv[])
{ 
        B b;    // line 1
	function(b); //line 2
	
}


Now, will the above code compile? if not, y?
na, that won't compile. what's c1? get() is const

function will not take B since B is not A. A is not a base class of B.

if you write
1
2
3
4
5
void function(const A& a)
{
	std::cout<<"Value of a is " <<c1.getA();
}

function() still does not take B. A does! Inside function() you cannot acces anything from B.

with this 'const' and b as paramter function() will create a local variable a where the constructor (const class B& a) is called

without this 'const' function() takes nothing but A since a could be modified.
Last edited on
Ok i am sorry again for that.. Now can u tell the problem with the following code?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "stdafx.h"
#include<iostream>

class B;

class A
{
public:
	A(class B& a)
	{
		std::cout<<"class B is converted to A";
	}
	void print()
	{
	}
};

class B
{
	int c;
public:
	void get()
	{
		c=10;
	}
};

void function(A& a)
{
	std::cout<<"Value of a is ";
	a.print();
}

int main(int argc, char* argv[])
{
	B b;
	function(b);
	return 0;
}
Coder777, stop spreading disinformation. Only post what you know for sure. I know for sure, that you allows implicit conversion from B to A by adding a single-argumented constructor in A that takes a B. The only problem is that you mix up your qualifiers a bit. Class should not be used inside a parameter declaration. Since this is kind of a strange conversion, we must ensure that no strange things happen, by making the input (B&) a constant value. (const B&)
Since this discards qualifiers for A::print(), we will have to make A::print() a constant function by suffixing it with const. (This means it cannot change values, and it's thus safe to use it, even on B. Finally, we change the A&, the function parameter, to const A&. You should get this result (note that the forward declaration is omitted since it's not needed in this context):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<iostream>


class B
{
    int c;
public:
    void get()
    {
        c=10;
    }
};

class A
{
public:
    A(const B& a)
    {
        std::cout<<"class B is converted to A";
    }
    void print() const
    {
    }
};


void function(const A& a)
{
    std::cout<<"Value of a is ";
    a.print();
}

int main(int argc, char** argv)
{
    B b;
    function(b);
    return 0;
}
Your function expect an A object passed by reference, but you are passing it by value.
He is not. Please stop posting if you don't know what you're talking about.
I'm confused
1
2
3
4
B b;
// are these the "same" ?
function(b);  //implicit conversion
function( A(b) );  //explicit conversion 

If I can do A(b).print() why is wrong to simplify by telling: "the constructor returns an object of that class"

The compiler yields (for the second one)
error: invalid initialization of non-const reference of type 'A&' from a temporary of type 'A'


EDIT: referred to karthick88's code
Last edited on
Try the code I gave you. And yes, you are right about the implicit and explicit conversions.
So guys.. Whats the answer to my question?
The code I posted earlier:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<iostream>


class B
{
    int c;
public:
    void get()
    {
        c=10;
    }
};

class A
{
public:
    A(const B& a)
    {
        std::cout<<"class B is converted to A";
    }
    void print() const
    {
    }
};


void function(const A& a)
{
    std::cout<<"Value of a is ";
    a.print();
}

int main(int argc, char** argv)
{
    B b;
    function(b);
    return 0;
}
karthick88 wrote:
Now can u tell the problem with the following code?
...
So guys.. Whats the answer to my question?


C++ has a rule regarding temporary objects: they're const. There is a good reason for this, but I won't get into that unless you really want to know.

Anyway, here's what that "temporary objects are const" bit means:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class A
{
public:
  A(int) { }
};


void c_func(const A& a)  {}  // a function that takes a const A
void nc_func(A& a) { } // a function that takes a non-const A

int main()
{
  // here's an example of calling the above WITHOUT a temporary object:
  A a(5);
  c_func(a);  // call it with our non-temporary 'A' object

  // this is an example of calling it with an explicit temporary
  c_func( A(5) );  // this creates a nameless, temporary A object, and passes it to the function
      // the temporary object is destroyed as soon as c_func returns.  It no longer exists

  // this is an example of calling it with an implicit temporary
  c_func( 5 );  // this is the exactly same as above "explicit" call.  a temporary A object is created and passed

  /*
    The kicker is... these temporary objects are always const.  Therefore the above all work because the
    function takes a const A as a parameter.  However nc_func takes a non-const A, so it doesn't work with temporaries
  */

  nc_func( a );  // OK, 'a' is non temporary and non-const, so the call is OK
  nc_func( A(5) );  // ERROR, the temporary object is const, and the function takes a non-const param!  
  nc_func( 5 );  // ERROR, for same reason as above
}



So the solution to your problem is:

1) make the function take a const reference instead of a nonconst reference (as Kyon illustrated)
or
2) don't use a temporary object.
Last edited on
There is a good reason for this, but I won't get into that unless you really want to know.

This has made me curious to dig the reason out from you..!! could you please put it out here?
Pages: 12