473,406 Members | 2,816 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Design Question: Inheritance or Accessors

Hi everybody,

I know this is not usually the place for design questions, but I was wondering what some of you more experienced people would do.

Say I have an application that has a C++ & STL core, with a user interface that could be command-line (on topic, I guess) or even .NET/QT/Whatever UI (obviously off-topic, here).

One of the classes in the core stores some data, in a vector. I want to display that information to the user.

Is it preferable to provide an accessor for the private data, e.g.:

std::vector<T> GetData() const {
return storage_;
}

With which the UI can obtain the data - which obviously loses some of my encapsulation, or would it be preferable to make the storage protected, and have the UI component inherit
from the class (probably multiple inheritance required in this case)?

I would prefer not to have any dependency of the UI within the core, so making the UI a friend would be difficult.

Cheers!

Ben
--
I'm not just a number. To many, I'm known as a String...
Jul 24 '05 #1
8 1428

"Ben Pope" <benpope81@_REMOVE_gmail.com> wrote in message
news:1122234898.3f87a0a1ac3b33b90f608e8290e7df8e@t eranews...
Hi everybody,

I know this is not usually the place for design questions, but I was
wondering what some of you more experienced people would do.

Say I have an application that has a C++ & STL core, with a user interface
that could be command-line (on topic, I guess) or even .NET/QT/Whatever UI
(obviously off-topic, here).

One of the classes in the core stores some data, in a vector. I want to
display that information to the user.

Is it preferable to provide an accessor for the private data, e.g.:

std::vector<T> GetData() const {
return storage_;
}


I would return const reference to data. This way one cannot change it.

const std::vector<T>& GetData() const
{
return storage_;
}

Dan
Jul 24 '05 #2
"Ben Pope" <benpope81@_REMOVE_gmail.com> wrote in message
news:1122234898.3f87a0a1ac3b33b90f608e8290e7df8e@t eranews...
Hi everybody,

I know this is not usually the place for design questions, but I was
wondering what some of you more experienced people would do.

Say I have an application that has a C++ & STL core, with a user interface
that could be command-line (on topic, I guess) or even .NET/QT/Whatever UI
(obviously off-topic, here).

One of the classes in the core stores some data, in a vector. I want to
display that information to the user.

Is it preferable to provide an accessor for the private data, e.g.:

std::vector<T> GetData() const {
return storage_;
}

With which the UI can obtain the data - which obviously loses some of my
encapsulation, or would it be preferable to make the storage protected,
and have the UI component inherit from the class (probably multiple
inheritance required in this case)?

I would prefer not to have any dependency of the UI within the core, so
making the UI a friend would be difficult.

Cheers!

Ben
--
I'm not just a number. To many, I'm known as a String...


I would give the user some iterators:

template <typename T>
class YourClass {
public:
typedef std::vector<T> t_container;
typedef t_container::const_iterator const_iterator;
const_iterator begin() const {return storage_.begin();}
const_iterator end() const {return storage_.end();}
....
};

A smart client should be able to write his code in such a way that nothing
breaks if you change to a different container type.

--
Cy
http://home.rochester.rr.com/cyhome/
Jul 24 '05 #3
Dan Cernat wrote:
"Ben Pope" <benpope81@_REMOVE_gmail.com> wrote in message
news:1122234898.3f87a0a1ac3b33b90f608e8290e7df8e@t eranews...
Is it preferable to provide an accessor for the private data, e.g.:

std::vector<T> GetData() const {
return storage_;
}

I would return const reference to data. This way one cannot change it.

const std::vector<T>& GetData() const
{
return storage_;
}


You'd prefer const reference over copy by value?

My original question was going to be over this particular issue, but I thought by-value was generally preferred, and then I thought of the inheritance thing, and wondered about
that "more".

Cheers,

Ben
--
I'm not just a number. To many, I'm known as a String...
Jul 24 '05 #4
Cy Edmunds wrote:
"Ben Pope" <benpope81@_REMOVE_gmail.com> wrote in message
news:1122234898.3f87a0a1ac3b33b90f608e8290e7df8e@t eranews...
Is it preferable to provide an accessor for the private data, e.g.:

std::vector<T> GetData() const {
return storage_;
}


I would give the user some iterators:

template <typename T>
class YourClass {
public:
typedef std::vector<T> t_container;
typedef t_container::const_iterator const_iterator;
const_iterator begin() const {return storage_.begin();}
const_iterator end() const {return storage_.end();}
...
};

A smart client should be able to write his code in such a way that nothing
breaks if you change to a different container type.


Hmm, interesting. I had toyed briefly with that idea, but hadn't formulated any real ideas.

I suppose the whole point is not to return the vector, giving access to the iterators, but to return the iterators themselves.

Is it possible to return a "forward container"? I don't see that as some concrete interface or base class anywhere in the STL, I presume it's "just" a concept, not tangible?

I suppose I could enforce a similar effect by doing:

typedef t_container::forward_iterator forward_iterator;

And if I wanted to be able to do:
*(YourClass.begin() + 4);

typedef t_container::random_access_iterator random_access_iterator;

This is very interesting.

I must re-read some of the STL concepts with a different hat on (one that asks how I would give my class these concepts, rather then how I can use these concepts).

Thank you.

Ben
--
I'm not just a number. To many, I'm known as a String...
Jul 24 '05 #5
Ben Pope wrote:
Cy Edmunds wrote:
I would give the user some iterators:

template <typename T>
class YourClass {
public:
typedef std::vector<T> t_container;
typedef t_container::const_iterator const_iterator;
const_iterator begin() const {return storage_.begin();}
const_iterator end() const {return storage_.end();}
...
};

A smart client should be able to write his code in such a way that
nothing breaks if you change to a different container type.

Hmm, interesting. I had toyed briefly with that idea, but hadn't
formulated any real ideas.

I suppose the whole point is not to return the vector, giving access to
the iterators, but to return the iterators themselves.


Just for a laugh, say I wanted to implement that storage stuff as part of a policy, should I be doing something like the following?

#include <vector>

typedef unsigned short uint16;
typedef unsigned char uint8;

/**
* Storage Policy based on a std::vector.
*/
template<class T>
class VectorStorage {
public:
typedef std::vector<T> t_container;
typedef typename t_container::size_type size_type;
typedef typename t_container::const_iterator const_iterator;

const_iterator begin() const {return storage_.begin();}
const_iterator end() const {return storage_.end();}
private:
t_container storage_;
};

/**
* Storage Policy based on an array.
*/
template<typename T>
class ArrayStorage {
public:
typedef T* t_container;
typedef uint16 size_type;
typedef const T* const_iterator;

ArrayStorage(size_type size = 8) : size_(size), storage_(new T[size]) {}
~ArrayStorage() {delete[] storage_;}

const_iterator begin() const {return storage_;}
const_iterator end() const {return storage_ + size_;}
private:
size_type size_;
t_container storage_;
};

....not that I'd want to use an array, usually, but if for some strange reason...

That would seem to abstract my implementation of storage_ from the user of the class, wouldn't it?

I could then publicly inherit either of those classes, and specify which one with a template parameter.

Cheers!

Ben
--
I'm not just a number. To many, I'm known as a String...
Jul 25 '05 #6
"Ben Pope" <benpope81@_REMOVE_gmail.com> wrote in message
news:1122250402.ba1ed96ef1ac23d9b40f5f5f364f5a1b@t eranews...
Ben Pope wrote:
Cy Edmunds wrote:
I would give the user some iterators:

template <typename T>
class YourClass {
public:
typedef std::vector<T> t_container;
typedef t_container::const_iterator const_iterator;
const_iterator begin() const {return storage_.begin();}
const_iterator end() const {return storage_.end();}
...
};

A smart client should be able to write his code in such a way that
nothing breaks if you change to a different container type.

Hmm, interesting. I had toyed briefly with that idea, but hadn't
formulated any real ideas.

I suppose the whole point is not to return the vector, giving access to
the iterators, but to return the iterators themselves.


The point is to make your classes maintainable by not putting implementation
details (such as which container you decided to use) right at the interface.
For instance if you started with std::vector but later decided to switch to
ArrayStorage no client code should break.

Just for a laugh, say I wanted to implement that storage stuff as part of
a policy, should I be doing something like the following?

#include <vector>

typedef unsigned short uint16;
typedef unsigned char uint8;

/**
* Storage Policy based on a std::vector.
*/
template<class T>
class VectorStorage {
public:
typedef std::vector<T> t_container;
typedef typename t_container::size_type size_type;
typedef typename t_container::const_iterator const_iterator;

const_iterator begin() const {return storage_.begin();}
const_iterator end() const {return storage_.end();}
private:
t_container storage_;
};

/**
* Storage Policy based on an array.
*/
template<typename T>
class ArrayStorage {
public:
typedef T* t_container;
typedef uint16 size_type;
Hm, just wondering why you would limit your array size to 32K elements. I
would probably use size_t here.
typedef const T* const_iterator;

ArrayStorage(size_type size = 8) : size_(size), storage_(new T[size])
{}
You should declare this one explicit -- you don't really want automatic
conversion from uint16 to ArrayStorage<T>.
~ArrayStorage() {delete[] storage_;}
Now you must include
ArrayStorage(const ArrayStorage<T> &);
and
ArrayStorage &operator = (const ArrayStorage<T> &);

Otherwise innocent looking code like
ArrayStorage<int> a1(3);
ArrayStorage<int> a2(a1);

will cause undefined behavior when storage_ gets deleted twice. Boost has a
reference counted smart pointer for arrays which might do what you want as
far as copy semantics are concerned.

const_iterator begin() const {return storage_;}
const_iterator end() const {return storage_ + size_;}
private:
size_type size_;
t_container storage_;
};

...not that I'd want to use an array, usually, but if for some strange
reason...

That would seem to abstract my implementation of storage_ from the user of
the class, wouldn't it?

I could then publicly inherit either of those classes, and specify which
one with a template parameter.
Better yet, you could encapsulate this object in your new object. This one
wasn't really made as a base class. For instance, no virtual destructor. I
think encapsulation should generally be preferred over inheritance with a
concrete data type like this.

Cheers!

Ben
--
I'm not just a number. To many, I'm known as a String...


--
Cy
http://home.rochester.rr.com/cyhome/
Jul 25 '05 #7


Ben Pope wrote:
Dan Cernat wrote:
"Ben Pope" <benpope81@_REMOVE_gmail.com> wrote in message
news:1122234898.3f87a0a1ac3b33b90f608e8290e7df8e@t eranews...
Is it preferable to provide an accessor for the private data, e.g.:

std::vector<T> GetData() const {
return storage_;
}

I would return const reference to data. This way one cannot change it.

const std::vector<T>& GetData() const
{
return storage_;
}


You'd prefer const reference over copy by value?

My original question was going to be over this particular issue, but I thought by-value was generally preferred, and then I thought of the inheritance thing, and wondered about
that "more".

Cheers,

Ben
--
I'm not just a number. To many, I'm known as a String...


think of std::string::c_str() method. It returns a pointer to the
internal data.

Dan

Jul 25 '05 #8
Ben Pope wrote:
Is it possible to return a "forward container"? I don't see
that as some concrete interface or base class anywhere in the
STL, I presume it's "just" a concept, not tangible?

I suppose I could enforce a similar effect by doing:

typedef t_container::forward_iterator forward_iterator;

And if I wanted to be able to do:
*(YourClass.begin() + 4);

typedef t_container::random_access_iterator
random_access_iterator;


The standard containers don't have such members. Rather, a given
container type's iterators belong to a specific category (and its
restrictions). Read http://www.sgi.com/tech/stl/iterator_tags.html.
If you want your class always to provide iterators of a given
category, you will have to adapt in the storage policy for a
container type with less capable iterators.
Martin

--
Quidquid latine dictum sit, altum viditur.
Jul 26 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Gert Van den Eynde | last post by:
Hi all, I have a question on interface design: I have a set of objects that are interlinked in the real world: object of class A needs for example for the operator() an object of class B. On...
5
by: Tony Johansson | last post by:
Hello!! Assume we have the following a base class called Weapon and three derived classes called MooseRifle, Winchester and Shotgun. These weapons have the followings attributes a name and a...
2
by: Tony Johansson | last post by:
Hello Experts!! Here we use multiple inheritance from two classes.We have a class named Person at the very top and below this class we have a Student class and an Employee class at the same...
0
by: JKJ | last post by:
I'm not an OOP guru, but I would say ". . .not necessarily" What if the base class and derived classes are internal? Then the base class has to be within the same assembly to be inherited from. ...
22
by: Matthew Louden | last post by:
I want to know why C# doesnt support multiple inheritance? But why we can inherit multiple interfaces instead? I know this is the rule, but I dont understand why. Can anyone give me some concrete...
21
by: yeti349 | last post by:
Hi, I'm using the following code to retrieve data from an xml file and populate a javascript array. The data is then displayed in html table form. I would like to then be able to sort by each...
24
by: Kalpesh | last post by:
Hello All, Please help validate this design problem Assume that I have several entities in my project (eg Supplier, Customer etc). All of them save several common properties - name, address,...
23
by: JoeC | last post by:
I am a self taught programmer and I have figured out most syntax but desigining my programs is a challenge. I realize that there are many ways to design a program but what are some good rules to...
2
by: sandyw | last post by:
Hello Everyone. This is my 2nd to last project and I need this one in order to do the last project which will be inheritance. Anyway... I have a project in which we need to create an application...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.