473,387 Members | 1,892 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,387 software developers and data experts.

Aggregating ABC's and pointer correctness

Greetings,

I've been reading Scott Meyer's book, "Effective C++", and I think
that I've confused myself terribly. I have a class like this:

class Tile
{
private:
Enchantment* m_ench;
Army* m_occupant;
ResourceType m_land_type;
Feature* m_feature;
Gate* m_gate;

public:
Tile();
Army* Occupant() const;
void Occupant(Army* occupant);

Enchantment* TileEnchantment() const;
void TileEnchantment(Enchantment* ench);

ResourceType LandType() const;
void LandType(const ResourceType& land_type);

void SetGate(Gate* new_gate);
Gate* GetGate() const;

void SetFeature(Feature* feature);
Feature* GetFeature() const;

~Tile();
};

Enchantment, Feature, Army, and Gate are all abstract base classes
(ABC's). My question is this: what is the best way to implement
accessors of those fields? According to Items 29 and 30, this sort of
implementation is out because it returns a handle to internal data
that is less accessible than itself:

Gate* Tile::GetGate() const
{
return m_gate;
}

But according to item 31, this is out too because it dereferences a
pointer initialized within a function:

Gate* Tile::GetGate() const
{
return m_gate.copy(); //Where copy returns a pointer to an object
created by new
}

What are my options? Should I return const references instead? I
suppose that I could return std::tr1::shared_ptr's, but I have to
believe that someone had a solution to this problem before that was
invented that didn't involve handles to internal data or memory leaks.

Thanks for your help.

Jun 3 '07 #1
7 1325
Tigera <ti****@rocketmail.comwrote:
I've been reading Scott Meyer's book, "Effective C++", and I think
that I've confused myself terribly. I have a class like this:

class Tile
{
private:
Enchantment* m_ench;
Army* m_occupant;
ResourceType m_land_type;
Feature* m_feature;
Gate* m_gate;

public:
Tile();
Army* Occupant() const;
void Occupant(Army* occupant);

Enchantment* TileEnchantment() const;
void TileEnchantment(Enchantment* ench);

ResourceType LandType() const;
void LandType(const ResourceType& land_type);

void SetGate(Gate* new_gate);
Gate* GetGate() const;

void SetFeature(Feature* feature);
Feature* GetFeature() const;

~Tile();
};

Enchantment, Feature, Army, and Gate are all abstract base classes
(ABC's). My question is this: what is the best way to implement
accessors of those fields? According to Items 29 and 30, this sort of
implementation is out because it returns a handle to internal data
that is less accessible than itself:
Is the Gate object less accessible than the Tile object? What other
objects hold the Gate object?
Gate* Tile::GetGate() const
{
return m_gate;
}
The above won't even compile. :-) Either the return has to be const or
the method can't be.
But according to item 31, this is out too because it dereferences a
pointer initialized within a function:

Gate* Tile::GetGate() const
{
return m_gate.copy(); //Where copy returns a pointer to an object
created by new
}

What are my options?
The most obvious option is to not have a "GetGate()" function. Move the
code that would use "GetGate()" into Tile.
Jun 3 '07 #2
Tigera wrote:
>
What are my options? Should I return const references instead? I
suppose that I could return std::tr1::shared_ptr's, but I have to
believe that someone had a solution to this problem before that was
invented that didn't involve handles to internal data or memory leaks.
There's internal data, and then there's internal data. An object that
aggregates other objects technically has internal data, but there's no
harm in allowing direct access to that data. Think of a vector<int>,
which lets you change the value of the nth element of the vector. On the
other hand, allowing user code to modify the pointer that points to the
vector's storage array could easily lead to disasters. That's because
the internal pointer is part of the implementation, and shouldn't be
exposed.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
Jun 3 '07 #3
On Jun 3, 2:17 pm, "Daniel T." <danie...@earthlink.netwrote:
Tigera <tig...@rocketmail.comwrote:
I've been reading Scott Meyer's book, "Effective C++", and I think
that I've confused myself terribly. I have a class like this:
class Tile
{
private:
Enchantment* m_ench;
Army* m_occupant;
ResourceType m_land_type;
Feature* m_feature;
Gate* m_gate;
public:
Tile();
Army* Occupant() const;
void Occupant(Army* occupant);
Enchantment* TileEnchantment() const;
void TileEnchantment(Enchantment* ench);
ResourceType LandType() const;
void LandType(const ResourceType& land_type);
void SetGate(Gate* new_gate);
Gate* GetGate() const;
void SetFeature(Feature* feature);
Feature* GetFeature() const;
~Tile();
};
Enchantment, Feature, Army, and Gate are all abstract base classes
(ABC's). My question is this: what is the best way to implement
accessors of those fields? According to Items 29 and 30, this sort of
implementation is out because it returns a handle to internal data
that is less accessible than itself:

Is the Gate object less accessible than the Tile object? What other
objects hold the Gate object?
Gate* Tile::GetGate() const
{
return m_gate;
}

The above won't even compile. :-) Either the return has to be const or
the method can't be.
But according to item 31, this is out too because it dereferences a
pointer initialized within a function:
Gate* Tile::GetGate() const
{
return m_gate.copy(); //Where copy returns a pointer to an object
created by new
}
What are my options?

The most obvious option is to not have a "GetGate()" function. Move the
code that would use "GetGate()" into Tile.
Ah, but sir, under gcc-4.1.2, it really did compile! Now, mind you I
only have it compiling at this point, and the program using this isn't
doing anything yet, so it remains to be seen if it will actually
work. I believe that you may be confusing the implementation with
something like:

const Gate* Tile::GetGate() const

In that case, you'd be right - I couldn't simply return it without a
const_cast.

Hey, what if I return a const Gate& instead? I guess that might still
give me a memory leak. My understanding from the book is that's like
std::string::c_str() is implemented.

Jun 3 '07 #4
Tigera <ti****@rocketmail.comwrote:
Gate* Tile::GetGate() const
{
return m_gate;
}
The above won't even compile. :-) Either the return has to be const or
the method can't be.

Ah, but sir, under gcc-4.1.2, it really did compile!
My mistake. It is the pointer that would have to be const, not the value
the pointer points to.
Jun 3 '07 #5
On Jun 3, 2:54 pm, Pete Becker <p...@versatilecoding.comwrote:
Tigera wrote:
What are my options? Should I return const references instead? I
suppose that I could return std::tr1::shared_ptr's, but I have to
believe that someone had a solution to this problem before that was
invented that didn't involve handles to internal data or memory leaks.

There's internal data, and then there's internal data. An object that
aggregates other objects technically has internal data, but there's no
harm in allowing direct access to that data. Think of a vector<int>,
which lets you change the value of the nth element of the vector. On the
other hand, allowing user code to modify the pointer that points to the
vector's storage array could easily lead to disasters. That's because
the internal pointer is part of the implementation, and shouldn't be
exposed.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
I guess that I could make the argument that the whole point of the
Tile class (which represents an area on a map) is that it's just a
storage location for those three members. But it still doesn't get
past Item 30. As Scott Meyers put it, "your overworked, underpaid
compilers went to lots of trouble to make sure your access
restrictions aren't circumvented." After all, Tile is the "owner" of
the pointer (i.e, it's responsible for allocating and deleting the
memory), at least that's the current design.
Maybe my only option really is to move the Gate/Enchantment/Army
functions to Tile and avoid anyone ever seeing those classes at all.

Jun 4 '07 #6
Tigera wrote:
On Jun 3, 2:54 pm, Pete Becker <p...@versatilecoding.comwrote:
>Tigera wrote:
>>What are my options? Should I return const references instead? I
suppose that I could return std::tr1::shared_ptr's, but I have to
believe that someone had a solution to this problem before that was
invented that didn't involve handles to internal data or memory leaks.
There's internal data, and then there's internal data. An object that
aggregates other objects technically has internal data, but there's no
harm in allowing direct access to that data. Think of a vector<int>,
which lets you change the value of the nth element of the vector. On the
other hand, allowing user code to modify the pointer that points to the
vector's storage array could easily lead to disasters. That's because
the internal pointer is part of the implementation, and shouldn't be
exposed.
[quoted sig elided]
I guess that I could make the argument that the whole point of the
Tile class (which represents an area on a map) is that it's just a
storage location for those three members. But it still doesn't get
past Item 30. As Scott Meyers put it, "your overworked, underpaid
compilers went to lots of trouble to make sure your access
restrictions aren't circumvented." After all, Tile is the "owner" of
the pointer (i.e, it's responsible for allocating and deleting the
memory), at least that's the current design.
Maybe my only option really is to move the Gate/Enchantment/Army
functions to Tile and avoid anyone ever seeing those classes at all.
As they say in the army, if the map doesn't fit the terrain, trust the
terrain.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
Jun 4 '07 #7
Tigera <ti****@rocketmail.comwrote:
I guess that I could make the argument that the whole point of the
Tile class (which represents an area on a map) is that it's just a
storage location for those three members. But it still doesn't get
past Item 30. As Scott Meyers put it, "your overworked, underpaid
compilers went to lots of trouble to make sure your access
restrictions aren't circumvented." After all, Tile is the "owner" of
the pointer (i.e, it's responsible for allocating and deleting the
memory), at least that's the current design.
I ask again, is that really the case? Do Tile objects own the objects
pointed to by the pointer, or do other objects use those objects too? It
sounds like the latter is the case.
Maybe my only option really is to move the Gate/Enchantment/Army
functions to Tile and avoid anyone ever seeing those classes at all.
That's an option, not necessarily the best. You might want to move this
thread over to comp.object. It is more a discussion of OO design than
C++ coding.
Jun 4 '07 #8

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

Similar topics

3
by: Victor Irzak | last post by:
Hello, I have an ABC. it supports: ostream & operator << I also have a derived class that supports this operator. How can I call operator << of the base class for derived object??? Is it...
10
by: quantdev2004 | last post by:
Hi all, I have been deling with this kind of code: class Foo { public: void NonConstMethod() {} };
52
by: Douglas Garstang | last post by:
I can't believe I've been trying to work this out for hours now, and I can't believe I couldn't find someone asking for a similar solution in the newsgroups. No wonder I hate C so much, and every...
2
by: Yossarian | last post by:
Hi, I'm a bit confused about something, hopefully someone can put me straight. I'd like to be able to call a function which takes a pointer to pointer, have that function allocate memory and...
18
by: Joseph Turian | last post by:
Let's say I want to have an abstract base class define a method which all the subclasses will implement. However, I cannot use virtual methods (long story short: these objects are only 24 bytes...
1
by: ank | last post by:
Hi, all. I've come to think of the idea of automatic initialization/deinitialization of non-local reference count pointer. I've made an assumption that the user of the pointer only read...
2
by: ank | last post by:
Hi, all. I've come to think of the idea of automatic initialization/deinitialization of non-local reference count pointer. I've made an assumption that the user of the pointer only read...
11
by: Brian Gladman | last post by:
A lot of low level cryptographic code and some hardware cryptographic accelerators either fail completely or perform very poorly if their input, output and/or key storage areas in memory are not...
34
by: Umesh | last post by:
I want to extract a string abc*xyz from a text file. * indicates arbitrary no. of characters. I'm only able to do it when the string has definite no. of characters or the string length is...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
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
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...

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.