Problem with a friend declaration when migrating project


U

Uwe Kotyczka

When migrationg a project from Visual Studio 2003 to Visual Studio
2010 I found a problem with a friend declarition. To illustratte it
I wrote a small sample programm (complete code see below).

I have two classes, class A and class Property. Class Property has
an assignment operator: const Property& operator=(const double
dValue);

Class A has a member variable of type Property. Only in one
specific function of class A, say A::DoSetProperty, I want
that the property can be changed. Therefore I declared the
assignment operator of class Property private and made
A::DoSetProperty a friend function of class Property.

That worked fine in Visual Studio 2003, however when migrating
to Visual Studio 2010 the compiler complains that it can't
see the friend declaration of A::DoSetProperty, because
A::DoSetProperty is protected in class A.

As a workaround I can either make A::DoSetProperty public
(which is not what I want to do) or declare the complete
class A as a friend of class Property (which I do not wish
to do either). Or I make the assignment operator public,
but then it can be called in any function of class A and
not only in A::DoSetProperty.

What would be the best solution? I would prefer a clear design
over a workaround.

Here comes the complete sample code:


#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>

////////////////////////////////////////////////////////////
class Property;

////////////////////////////////////////////////////////////
class A
{
public:
A();
virtual ~A();
void SetProperty(const double dValue);
protected:
void DoSetProperty(const double dValue);
private:
Property* m_pProperty;
};

////////////////////////////////////////////////////////////
class Property
{
friend void A::DoSetProperty(const double dValue);
public:
Property();
virtual ~Property();
int GetValue() const;
private:
const Property& operator=(const double dValue);
int m_nValue;
};

////////////////////////////////////////////////////////////
A::A()
{
m_pProperty = new Property();
}

A::~A()
{
if (m_pProperty)
delete m_pProperty;
}
void A::SetProperty(const double dValue)
{
DoSetProperty(dValue);
}

void A::DoSetProperty(const double dValue)
{
if (m_pProperty)
*m_pProperty = dValue;
}

////////////////////////////////////////////////////////////
Property::property()
{
m_nValue = -1;
}

Property::~Property()
{
}

int Property::GetValue() const
{
return m_nValue;
}

const Property& Property::eek:perator=(const double dValue)
{
m_nValue = static_cast<int>(dValue);
return *this;
}

////////////////////////////////////////////////////////////
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
A testA;
testA.SetProperty(5.5);

return 0;
}
 
Ad

Advertisements

V

Victor Bazarov

I have two classes, class A and class Property. Class Property has
an assignment operator: const Property& operator=(const double
dValue);

Class A has a member variable of type Property. Only in one
specific function of class A, say A::DoSetProperty, I want
that the property can be changed. Therefore I declared the
assignment operator of class Property private and made
A::DoSetProperty a friend function of class Property.

That worked fine in Visual Studio 2003, however when migrating
to Visual Studio 2010 the compiler complains that it can't
see the friend declaration of A::DoSetProperty, because
A::DoSetProperty is protected in class A.

As a workaround I can either make A::DoSetProperty public
(which is not what I want to do) or declare the complete
class A as a friend of class Property (which I do not wish
to do either). Or I make the assignment operator public,
but then it can be called in any function of class A and
not only in A::DoSetProperty.

What would be the best solution? I would prefer a clear design
over a workaround.

You have a chicken and egg design problem. On one hand, your property
requires friendship to use its operator=. So, you solve it by making
the user of operator= (your 'A::DoSetProperty' function) a friend of
Property. On the other hand, access to 'A::DoSetProperty' is blocked as
well, so you need to give your Property some way to access it. You can
make Property a *derived class* of A, but that's not right, is it?

Declare class Property a friend of A. After all, in order to see A's
private (and protected) parts, Property has to be either a friend or a
relative. Another possibility is to get rid of the extra indirection
(the 'A::DoSetProperty' nonsense), leave only 'A::SetProperty' around
and let *that member* be a friend of Property. What's the reason to
have that 'DoSetProperty', anyway?

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top