using friend to enhance encapsulation?

R

Ruben Lysens

Hi,

Consider the example below. A Device controls a number of Ports. I'd
like the Device to be in charge of creating/deleting Ports. I enforce
this by making the Ports constructor and destructor private and making
Device a friend of Port. In Device's destructor I'd like to use a
generic purge function to delete all Ports. Ofcourse that doesn't work
because the Port destructor is private for Purge.
So, where did I go wrong? I went for the private ctor/dtor + friend
approach to keep things as encapsulated as possible. I can make Port's
ctor/dtor public, but ideally I don't want clients to be able to create
Ports. Alternatively, I could duplicate purge's functionality inside the
Device destructor, but that's not my favourite kind of code reuse. How
do you fix this design?

Ruben.

#include <vector>
#include <iostream>

using namespace std;

/*From Bruce Eckel's Thinking in C++ Vol.2.
*Belongs in a separate purge.h file*/
template<class Seq> void purge(Seq& c) {
typename Seq::iterator i;
for(i = c.begin(); i != c.end(); ++i) {
delete *i;
*i = 0;
}
}

class Device {
public:
class Port {
public:
void doSomething() {
cout << "port " << id_ << " doing something." << endl;
};
private:
int id_;
Device& device_;

Port(int id, Device &device) : id_(id), device_(device) {}

~Port() {
cout << "destructing port" << endl;
}

friend class Device;
};

Device(int numPorts) {
for (int i=0; i<numPorts; i++) {
ports_.push_back(new Port(i, *this));
}
}

~Device() {
purge(ports_);
}

Port* getPort(int i) {
return ports_.at(i);
}
private:
vector<Port*> ports_;
};

int main() {
Device device(10);
return 0;
}
 
I

Ivan Vecerina

Ruben Lysens said:
Consider the example below. A Device controls a number of Ports. I'd like
the Device to be in charge of creating/deleting Ports. I enforce this by
making the Ports constructor and destructor private and making Device a
friend of Port. In Device's destructor I'd like to use a generic purge
function to delete all Ports. Ofcourse that doesn't work because the Port
destructor is private for Purge.
So, where did I go wrong? I went for the private ctor/dtor + friend
approach to keep things as encapsulated as possible. I can make Port's
ctor/dtor public, but ideally I don't want clients to be able to create
Ports. Alternatively, I could duplicate purge's functionality inside the
Device destructor, but that's not my favourite kind of code reuse. How do
you fix this design?

Ruben.

#include <vector>
#include <iostream>

using namespace std;

/*From Bruce Eckel's Thinking in C++ Vol.2.
*Belongs in a separate purge.h file*/
template<class Seq> void purge(Seq& c) {
typename Seq::iterator i;
for(i = c.begin(); i != c.end(); ++i) {
delete *i;
*i = 0;
}
}

class Device {
public:
class Port {
public:
void doSomething() {
cout << "port " << id_ << " doing something." << endl;
};
private:
int id_;
Device& device_;

Port(int id, Device &device) : id_(id), device_(device) {}

~Port() {
cout << "destructing port" << endl;
}

friend class Device;
What about adding:
};

Device(int numPorts) {
for (int i=0; i<numPorts; i++) {
ports_.push_back(new Port(i, *this));
NB: This will leak memory if the creation of a >0th port
fails. You probably should use some kind of smart pointer,
or handle the exception to free previously created entries.
}
}

~Device() {
purge(ports_);
}

Port* getPort(int i) {
NB: I'd rather return a reference than a pointer here,
unless the stored pointer is actually allows to be null.
return ports_.at(i);
}
private:
vector<Port*> ports_;
};

int main() {
Device device(10);
return 0;
}

Regards,
Ivan
 
R

Ruben Lysens

Ivan said:
What about adding:
friend void purge(vector<Port*>&);
Not clean in terms of interdependencies, but safe.

This would allow users to delete Port objects by entering Port object
pointers into a vector and feeding that to purge. Then I prefer
duplicating the purge function as a member function over this solution.
Either way, the solution is ugly. So I suspect the design's no good,
maybe because I'm going about encapsulation and this friend feature the
wrong way. I don't have a lot of experience as a C++ programmer.

R.
 

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

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top