tags:

views:

271

answers:

7

I am not sure whether I am missing something basic. But I am unable to understand why the compiler is generating the error for this code:

class A
{
};

class B
{
public:
    B();
    A* get() const;

private:
    A* m_p;
};

B::B()
{
    m_p = new A;
}

A* B::get() const
{
    //This is compiling fine
    return m_p;
}

class C
{
public:
    A* get() const;
private:
    A m_a;
};

A* C::get() const
{
   //Compiler generates an error for this. Why? 
    return &m_a;
}

EDIT: The compiler error is : error C2440: 'return' : cannot convert from 'const class A *' to 'class A *' Conversion loses qualifiers

+2  A: 

It's because you're returning a non-const pointer to a member from a const function.

The first part works because you're returning a copy of a member pointer, so this doesn't violate the const-ness of the get function:

class B
{
public:
    B();
    A* get() const;

private:
    A* m_p;
};

A* B::get() const
{
    //This is compiling fine
    return m_p;
}

But the next bit generates the compile error (on gcc 4)

testfile.cpp:37: error: invalid conversion from ‘const A*’ to ‘A*’

Because your const get function is providing non-const acess to m_a by returning a non-const pointer to it.

class C
{
public:
    A* get() const;
private:
    A m_a;
};

A* C::get() const
{
   //Compiler generates an error for this. Why?
    return &m_a;
}
therefromhere
+11  A: 

const in the function signature tells the compiler that the object's members may not be modified. Yet you return a non-const pointer to a member, thus allowing a violation of that promise.

In your class B, you make/break no promise since you don't return a pointer to a member, you return a copy of it (and the member happens to be a pointer).

Konrad Rudolph
Yes..got it now. Looks so simple now.
Naveen
+1  A: 

Because the returned pointer is not const. Change it to this:

class C
{
public:
    const A* get() const;
private:
    A m_a;
};

const A* C::get() const
{
    //Compiler generates an error for this. Why? 
    return &m_a;
}

Notice that C::get() now returns a const pointer to A.

jn_
A: 

Member functions marked const cannot return a non-const reference or pointer to a private variable. If the compiler allowed this, anyone outside your class would be able to modify the said private variable and the const qualifier on the function would lose meaning.

Frederick
A: 

This problem can be illustrated with a simpler example:

class MyClass {
public:
    int *get() const;
private:
    int value;
};

int *MyClass::get() const {
    return &value;
}

In MyClass::get() const, value has the type const int. When you dereference it, you get const int *. That type cannot be safely (implicitly) casted to int *. To correct your problem, have get() return const int *.

strager
A: 
A* C::get() const
{
   //Compiler generates an error for this. Why? 
    return &m_a;
}

Because get() is a const function, the compiler treats all member variables it refers to as const. When you take the address of such a member, you get a pointer to const. But your function is returning a non-const pointer. You need to change your code to

const A* C::get() const
{
    return &m_a;
}
anon
A: 

Basically just add a const in front,

const A* C::get() const
{
   //Compiler generates an error for this. Why? 
    return &m_a;
}

Then if you want to access it, basically do:

C something;

const A* a = something.get();

However, your program makes very little sense, to me.

IMO, it would make most sense to do:

class A{
};

class C : public A
{
};

That way you don't have to make a "get" that returns the instance of A.

Daniel