Dear all,
Is there a clear distinction how to decide which functions to be
members of a class and which not
How is your attitude (Your general way from your experiences ...)
"If the function changes the state of the object, it ought to be a
member of that object." Reference Accelerated C++, A. Koenig, page 159.
Thx to you all. 39 2952
"utab" <um********@gmail.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com... "If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
Please note that "ought to be" is less strong than "should always be." It
means "make it a member unless you have a good reason to do otherwise."
One such reason might be a function that changes the state of two or more
objects of different classes. Such a function cannot possibly be members of
both objects. Moreover, such functions are not uncommon: operator>> is
probably the most widely used example.
So sometimes it's impossible to make state-changing functions members of
their objects. Still, it's nice to do so when there is a choice.
utab wrote: Dear all,
Is there a clear distinction how to decide which functions to be members of a class and which not
This isn't a C++ question....
How is your attitude (Your general way from your experiences ...)
"If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
I'm sure there are examples where this doesn't make since, but in
general I agree.
In article <Me******************@bgtnsc04-news.ops.worldnet.att.net>,
"Andrew Koenig" <ar*@acm.org> wrote: "utab" <um********@gmail.com> wrote in message news:11**********************@i39g2000cwa.googlegr oups.com...
"If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
Please note that "ought to be" is less strong than "should always be." It means "make it a member unless you have a good reason to do otherwise."
One such reason might be a function that changes the state of two or more objects of different classes. Such a function cannot possibly be members of both objects. Moreover, such functions are not uncommon: operator>> is probably the most widely used example.
So sometimes it's impossible to make state-changing functions members of their objects. Still, it's nice to do so when there is a choice.
I would go so far as to say that if the function changes the state of
two or more objects, it should not be in the class, even if both/all
objects are of the same type.
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
BigBrian wrote: Is there a clear distinction how to decide which functions to be members of a class and which not
This isn't a C++ question....
Mr. Manners reminds the Gentle Poster that replies should be on topic if
possible.
For example, C++ brings many special considerations to the question of
whether a function should be semantically a member of an object's
interface, or syntactically a member of its class. operator<<, as already
mention, is semantically a member of both the interfaces of your object and
of ostream. But it is syntactically not a member of your class's methods.
--
Phlip http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Daniel T. wrote: In article <Me******************@bgtnsc04-news.ops.worldnet.att.net>, "Andrew Koenig" <ar*@acm.org> wrote:
"utab" <um********@gmail.com> wrote in message news:11**********************@i39g2000cwa.googlegr oups.com...
"If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
Please note that "ought to be" is less strong than "should always be." It means "make it a member unless you have a good reason to do otherwise."
One such reason might be a function that changes the state of two or more objects of different classes. Such a function cannot possibly be members of both objects. Moreover, such functions are not uncommon: operator>> is probably the most widely used example.
So sometimes it's impossible to make state-changing functions members of their objects. Still, it's nice to do so when there is a choice.
I would go so far as to say that if the function changes the state of two or more objects, it should not be in the class, even if both/all objects are of the same type.
Actually, I strongly disagree. If it only concerns this particular type,
then the function _should_ be in the class. It should probably be static
of course.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
"utab" <um********@gmail.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com... Dear all,
Is there a clear distinction how to decide which functions to be members of a class and which not
How is your attitude (Your general way from your experiences ...)
"If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
Thx to you all.
Koenig's quote notwithstanding, there is an undesirable aspect of member
functions: they can depend on the implementation. This is sometimes called
"breaking encapsulation". This tends to reduce the maintainability of the
code because if the implementation changes there is more to do and more
mistakes to make. Consider:
void
SomeClass::notify_and_print()
{
notify(); // member function
print(); // another member function;
}
Classes like this which can be written entirely in terms of the rest of an
object's interface can be refactored out:
void
notify_and_print(SomeClass &c)
{
c.notify();
c.print();
}
Although both of these functions will continue to work if the implementation
changes, in the second case I KNOW this to be the case because the second
function has no access to the private parts of SomeClass (i.e. doesn't
"break encapsulation").
As a result of these considerations I usually don't allow member functions
which feature gratuitious access to the implementation. However, I certainly
make exceptions if the interface design seems to call for it.
Cy
In article <e2**********@news.datemas.de>,
"Victor Bazarov" <v.********@comAcast.net> wrote: Daniel T. wrote: In article <Me******************@bgtnsc04-news.ops.worldnet.att.net>, "Andrew Koenig" <ar*@acm.org> wrote:
"utab" <um********@gmail.com> wrote in message news:11**********************@i39g2000cwa.googlegr oups.com...
"If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
Please note that "ought to be" is less strong than "should always be." It means "make it a member unless you have a good reason to do otherwise."
One such reason might be a function that changes the state of two or more objects of different classes. Such a function cannot possibly be members of both objects. Moreover, such functions are not uncommon: operator>> is probably the most widely used example.
So sometimes it's impossible to make state-changing functions members of their objects. Still, it's nice to do so when there is a choice.
I would go so far as to say that if the function changes the state of two or more objects, it should not be in the class, even if both/all objects are of the same type.
Actually, I strongly disagree. If it only concerns this particular type, then the function _should_ be in the class. It should probably be static of course.
There are readability/writability factors involved. If the function is a
static class member, then it helps scope the function, although the
parameters do that so humm... why should it be static in the class?
As an example:
class Object {
public:
// whatever
};
// returns true if 'a' and 'b' have intersecting areas.
bool hit( Object& a, Object& b );
Why exactly _should_ 'hit' be a static in Object?
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Daniel T. wrote: In article <e2**********@news.datemas.de>, "Victor Bazarov" <v.********@comAcast.net> wrote:
Daniel T. wrote: In article <Me******************@bgtnsc04-news.ops.worldnet.att.net>, "Andrew Koenig" <ar*@acm.org> wrote:
"utab" <um********@gmail.com> wrote in message news:11**********************@i39g2000cwa.googlegr oups.com...
> "If the function changes the state of the object, it ought to be a > member of that object." Reference Accelerated C++, A. Koenig, page > 159.
Please note that "ought to be" is less strong than "should always be." It means "make it a member unless you have a good reason to do otherwise."
One such reason might be a function that changes the state of two or more objects of different classes. Such a function cannot possibly be members of both objects. Moreover, such functions are not uncommon: operator>> is probably the most widely used example.
So sometimes it's impossible to make state-changing functions members of their objects. Still, it's nice to do so when there is a choice.
I would go so far as to say that if the function changes the state of two or more objects, it should not be in the class, even if both/all objects are of the same type.
Actually, I strongly disagree. If it only concerns this particular type, then the function _should_ be in the class. It should probably be static of course.
There are readability/writability factors involved. If the function is a static class member, then it helps scope the function, although the parameters do that so humm... why should it be static in the class?
As an example:
class Object { public: // whatever };
// returns true if 'a' and 'b' have intersecting areas. bool hit( Object& a, Object& b );
Why exactly _should_ 'hit' be a static in Object?
Simply because when I see
hit(a, b);
I really have no idea what 'a' and 'b' are and which of fourteen 'hit'
functions is going to be used. If I see
Object::hit(a, b)
there is no doubt which function is used.
Another argument: limiting the name scope is impossible with arguments.
And limiting the scope of every name is what we should be doing all the
time. Polluting namespace scope with functions that do something very
specific to objects of a single class is... well, polluting.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
In article <e2**********@news.datemas.de>,
"Victor Bazarov" <v.********@comAcast.net> wrote: Daniel T. wrote: In article <e2**********@news.datemas.de>, "Victor Bazarov" <v.********@comAcast.net> wrote:
Daniel T. wrote: In article <Me******************@bgtnsc04-news.ops.worldnet.att.net>, "Andrew Koenig" <ar*@acm.org> wrote:
> "utab" <um********@gmail.com> wrote in message > news:11**********************@i39g2000cwa.googlegr oups.com... > >> "If the function changes the state of the object, it ought to be a >> member of that object." Reference Accelerated C++, A. Koenig, page >> 159. > > Please note that "ought to be" is less strong than "should always > be." It means "make it a member unless you have a good reason to > do otherwise." > > One such reason might be a function that changes the state of two > or more objects of different classes. Such a function cannot > possibly be members of both objects. Moreover, such functions are > not uncommon: operator>> is probably the most widely used example. > > So sometimes it's impossible to make state-changing functions > members of their objects. Still, it's nice to do so when there is > a choice.
I would go so far as to say that if the function changes the state of two or more objects, it should not be in the class, even if both/all objects are of the same type.
Actually, I strongly disagree. If it only concerns this particular type, then the function _should_ be in the class. It should probably be static of course. There are readability/writability factors involved. If the function is a static class member, then it helps scope the function, although the parameters do that so humm... why should it be static in the class?
As an example:
class Object { public: // whatever };
// returns true if 'a' and 'b' have intersecting areas. bool hit( Object& a, Object& b );
Why exactly _should_ 'hit' be a static in Object?
Simply because when I see
hit(a, b);
I really have no idea what 'a' and 'b' are and which of fourteen 'hit' functions is going to be used.
Seems to me that if you don't know what 'a' and 'b' are, you really
shouldn't be writing the code.
If I see
Object::hit(a, b)
there is no doubt which function is used.
The above is nothing more than a compiler enforced version of hungarian
notation.
Another argument: limiting the name scope is impossible with arguments. And limiting the scope of every name is what we should be doing all the time. Polluting namespace scope with functions that do something very specific to objects of a single class is... well, polluting.
Unless, of course, the namespace is for "things that work with Objects"
presumably...
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Cy Edmunds wrote: As a result of these considerations I usually don't allow member functions which feature gratuitious access to the implementation. However, I certainly
This has the disadvantage that the way in which the function is called
depends on whether or not it needs to access the implementation, i.e.
o.needs_acess();
vs,
doesnt_need_access(o);
This kind of breaks encapsulation too, as the interface of the class
depends on implementation details, namely, whether or not a particular
function requires access to the internals of the class. To get round
this, I've sometimes considered writing classes with no public member
functions at all. I've never actually written a whole program like
this, because it's sufficiently odd that it might constitute a
stumbling block for anyone else reading the code, but I'd be interested
in what others think of the idea. E.g:
class MyClass
{
private:
SomeClass data_;
virtual void do_operation();
friend void needs_access();
public:
explicit MyClass(SomeClass& d)
: data_(d)
{ }
virtual ~MyClass();
};
void needs_access(MyClass& c)
{
...
}
void doesnt_need_access(MyClass& c)
{
...
}
void do_operation(MyClass& c)
{
c.do_operation();
}
"I V" <wr******@gmail.com> wrote in message
news:11**********************@e56g2000cwe.googlegr oups.com... Cy Edmunds wrote: As a result of these considerations I usually don't allow member functions which feature gratuitious access to the implementation. However, I certainly This has the disadvantage that the way in which the function is called depends on whether or not it needs to access the implementation, i.e.
o.needs_acess();
vs,
doesnt_need_access(o);
This is true but sort of unavoidable. Sooner or later you will want to get
some sort of extended functionality and you only have two choices: derive a
new class with the member function you want, or just write another function:
didnt_think_of_this_at_first(o);
Deriving a new class just to get a new function is often a poor idea for a
lot of reasons. For example:
my_string : public std::string
{
public:
void my_leet_function();
};
Yech. This kind of breaks encapsulation too, as the interface of the class depends on implementation details, namely, whether or not a particular function requires access to the internals of the class.
This is certainly not what I would call breaking encapsulation. Actually I
don't see the problem here at all.
To get round this, I've sometimes considered writing classes with no public member functions at all. I've never actually written a whole program like this, because it's sufficiently odd that it might constitute a stumbling block for anyone else reading the code, but I'd be interested in what others think of the idea. E.g:
class MyClass { private: SomeClass data_;
virtual void do_operation(); friend void needs_access();
public: explicit MyClass(SomeClass& d) : data_(d) { }
virtual ~MyClass(); };
void needs_access(MyClass& c) { ... }
void doesnt_need_access(MyClass& c) { ... }
void do_operation(MyClass& c) { c.do_operation(); }
I think it would be a stumbling block for anyone else reading the code!
Also, if you have some reason to try to hide which things need access to the
internals and which things don't, this is hardly a solution.
Cy
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:e2**********@news.datemas.de... Daniel T. wrote: In article <e2**********@news.datemas.de>, "Victor Bazarov" <v.********@comAcast.net> wrote:
Daniel T. wrote: In article <Me******************@bgtnsc04-news.ops.worldnet.att.net>, "Andrew Koenig" <ar*@acm.org> wrote:
> "utab" <um********@gmail.com> wrote in message > news:11**********************@i39g2000cwa.googlegr oups.com... > >> "If the function changes the state of the object, it ought to be a >> member of that object." Reference Accelerated C++, A. Koenig, page >> 159. > > Please note that "ought to be" is less strong than "should always > be." It means "make it a member unless you have a good reason to > do otherwise." > > One such reason might be a function that changes the state of two > or more objects of different classes. Such a function cannot > possibly be members of both objects. Moreover, such functions are > not uncommon: operator>> is probably the most widely used example. > > So sometimes it's impossible to make state-changing functions > members of their objects. Still, it's nice to do so when there is > a choice.
I would go so far as to say that if the function changes the state of two or more objects, it should not be in the class, even if both/all objects are of the same type.
Actually, I strongly disagree. If it only concerns this particular type, then the function _should_ be in the class. It should probably be static of course. There are readability/writability factors involved. If the function is a static class member, then it helps scope the function, although the parameters do that so humm... why should it be static in the class?
As an example:
class Object { public: // whatever };
// returns true if 'a' and 'b' have intersecting areas. bool hit( Object& a, Object& b );
Why exactly _should_ 'hit' be a static in Object?
Simply because when I see
hit(a, b);
I really have no idea what 'a' and 'b' are and which of fourteen 'hit' functions is going to be used. If I see
Object::hit(a, b)
there is no doubt which function is used.
I think this argument is a giant stretch but even if I were to buy it what
if you later need some other functionality? You can always write your own
bool miss( Object& a, Object& b );
but you may not be able to add you own static function. That's why I favor
making the interface as simple as possible and using stand alone functions,
overloaded if necessary.
If you really want to insist on qualifiers you can use namespaces:
namespace dubious
{
bool miss( Object& a, Object& b );
}
dubious::miss(a, b);
Kinda dumb, but at least it is extendable. Another argument: limiting the name scope is impossible with arguments. And limiting the scope of every name is what we should be doing all the time. Polluting namespace scope with functions that do something very specific to objects of a single class is... well, polluting.
V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask
Cy Edmunds wrote: [...] If you really want to insist on qualifiers you can use namespaces:
namespace dubious { bool miss( Object& a, Object& b ); }
dubious::miss(a, b);
Kinda dumb, but at least it is extendable.
No more and no less than classes. I can always wrap one class in another
to "add functionality" AFA static members are concerned.
Classes are not namespaces and namespaces are not classes. Substituting
one for the other just for the sake of substituting is pointless. Any
functionality specific to a class belongs to the class.
V
--
Please remove capital As from my address when replying by mail
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:Ne********************@comcast.com... Cy Edmunds wrote: [...] If you really want to insist on qualifiers you can use namespaces:
namespace dubious { bool miss( Object& a, Object& b ); }
dubious::miss(a, b);
Kinda dumb, but at least it is extendable.
No more and no less than classes. I can always wrap one class in another to "add functionality" AFA static members are concerned.
Classes are not namespaces and namespaces are not classes. Substituting one for the other just for the sake of substituting is pointless. Any functionality specific to a class belongs to the class.
I agree with everything you said except the last sentence. In C++ there is
no reason to break encapsulation just because you want to add some
functionality.
Cy
Cy Edmunds wrote: [..] In C++ there is no reason to break encapsulation just because you want to add some functionality.
I've read that expression several times today, and still have not
understood how putting functionality that specific to any particular
class inside that class means "breaking encapsulation". Care to
elaborate?
V
--
Please remove capital As from my address when replying by mail
In article <11**********************@i39g2000cwa.googlegroups .com>,
"utab" <um********@gmail.com> wrote: Dear all,
Is there a clear distinction how to decide which functions to be members of a class and which not
How is your attitude (Your general way from your experiences ...)
"If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
An important point that I think needs to be mentioned. No
member-function should return with the class invariant broken (however
it can break the invariant inside itself.)
So for example:
class Range {
// invariant: low() < high()
public:
int low() const;
int high() const;
void setLow( int v );
// postcondition: low() == v
};
The 'setLow' member-function above has a real problem, it can't
guarantee it's postcondition and its invariant unless the user of the
class first checks to see if the value passed in is less than 'high()'.
Many new programmers, will ignore this glaring problem, some will add an
assert( v < high() ) or throw and exception if v >= high() and think
they are clever, but neither "solution" really solves the problem. The
user of the class must still do most of the work ensuring the invariant
stays true (and that is supposed to be the class' responsibility.)
There are only two solutions, either 'setLow's precondition needs to
change to something that works [ like: low() == min( v, high() - 1 ) ],
or the function needs to go away.
To generalize this rule. Anytime a member-function *requires* the object
to be in a particular state in order to be called, the member-function
is poorly formed and needs to be fixed or removed.
--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Cy Edmunds wrote: "I V" <wr******@gmail.com> wrote in message This has the disadvantage that the way in which the function is called depends on whether or not it needs to access the implementation, i.e.
o.needs_acess();
vs,
doesnt_need_access(o);
This is true but sort of unavoidable. Sooner or later you will want to get some sort of extended functionality and you only have two choices: derive a new class with the member function you want, or just write another function:
Well, that makes me wonder if having a special syntax for calling
member functions is actually a good thing. After all, why should it
matter to the user of the class if the operation on an object is
defined by the class or by some later code? Combining the idea of
"requires access to class internals," "is part of the class's
interface" and "is an operation on objects of the class" into one
syntax is, perhaps, confusing.
I belive in the Dylan language, obj.meth(arg) is just syntactic sugar
for meth(obj, arg) , which strikes me as quite an attractive design (in
Dylan, you define a function which does dynamic dispatch on the types
of its arguments outside of a class definition). This kind of breaks encapsulation too, as the interface of the class depends on implementation details, namely, whether or not a particular function requires access to the internals of the class.
This is certainly not what I would call breaking encapsulation. Actually I don't see the problem here at all.
Whether a function needs access to the internals of a class depends on
the implementation, no? A maybe interesting example is a class with two
methods, each of which can be implemented in terms of the other; thus,
which you make access the class internals is a matter of choice. If you
make one a member function and one a non-member, you're exposing this
choice in the interface, which sounds like breaking encapsulation to
me. Certainly, if you later decide to change your implementation
(perhaps implementing function A in terms of function B turns out to be
more efficient than the other way round), making one a member and the
other a non-member will cause you problems.
Victor Bazarov wrote: Cy Edmunds wrote:
[..] In C++ there is no reason to break encapsulation just because you want to add some functionality.
I've read that expression several times today, and still have not understood how putting functionality that specific to any particular class inside that class means "breaking encapsulation". Care to elaborate?
If you add functionality to a class via (non-friend) non-members, then
that functionality necessarily only depends on the public interface of
the class.
Tom
Tom Widmer wrote: Victor Bazarov wrote: Cy Edmunds wrote:
[..] In C++ there is no reason to break encapsulation just because you want to add some functionality.
I've read that expression several times today, and still have not understood how putting functionality that specific to any particular class inside that class means "breaking encapsulation". Care to elaborate?
If you add functionality to a class via (non-friend) non-members, then that functionality necessarily only depends on the public interface of the class.
Yes, and?... Where is the "breaking" part? If the functionality is
instead actually _part_ of public interface, what's broken? Or is adding
to a class' interface in fact "breaking" some fragile "encapsulation"?
What is the essential difference between
class A {
// some interface, public or otherwise
};
void foo(A& a) {
// some implemenation
}
and
class A {
// some interface, public or otherwise
static void foo(A& a) {
// same implemenation as above
}
};
What is broken in the second case compared to the first one?
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:e2**********@news.datemas.de... Tom Widmer wrote: Victor Bazarov wrote: Cy Edmunds wrote:
[..] In C++ there is no reason to break encapsulation just because you want to add some functionality.
I've read that expression several times today, and still have not understood how putting functionality that specific to any particular class inside that class means "breaking encapsulation". Care to elaborate?
If you add functionality to a class via (non-friend) non-members, then that functionality necessarily only depends on the public interface of the class.
Yes, and?... Where is the "breaking" part? If the functionality is instead actually _part_ of public interface, what's broken? Or is adding to a class' interface in fact "breaking" some fragile "encapsulation"?
What is the essential difference between
class A { // some interface, public or otherwise };
void foo(A& a) { // some implemenation }
and
class A { // some interface, public or otherwise static void foo(A& a) { // same implemenation as above } };
What is broken in the second case compared to the first one?
V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask
In the second case a mistake in the implementation of foo can result in
violation of invariants of the class.
Cy Edmunds wrote: "Victor Bazarov" <v.********@comAcast.net> wrote in message news:e2**********@news.datemas.de... Tom Widmer wrote: Victor Bazarov wrote: Cy Edmunds wrote:
> [..] In C++ > there is no reason to break encapsulation just because you want to > add some functionality.
I've read that expression several times today, and still have not understood how putting functionality that specific to any particular class inside that class means "breaking encapsulation". Care to elaborate?
If you add functionality to a class via (non-friend) non-members, then that functionality necessarily only depends on the public interface of the class.
Yes, and?... Where is the "breaking" part? If the functionality is instead actually _part_ of public interface, what's broken? Or is adding to a class' interface in fact "breaking" some fragile "encapsulation"? What is the essential difference between
class A { // some interface, public or otherwise };
void foo(A& a) { // some implemenation }
and
class A { // some interface, public or otherwise static void foo(A& a) { // same implemenation as above } };
What is broken in the second case compared to the first one?
V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask
In the second case a mistake in the implementation of foo can result in violation of invariants of the class.
Yes, I agree. Is that the whole thing or there's something else?
If that's the whole thing, then in my book the benefits of limiting the
scope of functionality outweigh the benefits of preventing my potential
mistakes while implementing 'foo'. *I* do not make any. The users of
my classes OTOH do. And they make mistakes mostly because of an unclear
intentions, communicated poorly by placing functionality in overly broad
scopes.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
"I V" <wr******@gmail.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com... Cy Edmunds wrote: "I V" <wr******@gmail.com> wrote in message > This has the disadvantage that the way in which the function is called > depends on whether or not it needs to access the implementation, i.e. > > o.needs_acess(); > > vs, > > doesnt_need_access(o); This is true but sort of unavoidable. Sooner or later you will want to get some sort of extended functionality and you only have two choices: derive a new class with the member function you want, or just write another function:
Well, that makes me wonder if having a special syntax for calling member functions is actually a good thing.
You certainly have a good point there. Still, if we are going to program in
C++ we need to deal with it as it actually is.
After all, why should it matter to the user of the class if the operation on an object is defined by the class or by some later code? Combining the idea of "requires access to class internals," "is part of the class's interface" and "is an operation on objects of the class" into one syntax is, perhaps, confusing.
I belive in the Dylan language, obj.meth(arg) is just syntactic sugar for meth(obj, arg) , which strikes me as quite an attractive design (in Dylan, you define a function which does dynamic dispatch on the types of its arguments outside of a class definition).
> This kind of breaks encapsulation too, as the interface of the class > depends on implementation details, namely, whether or not a particular > function requires access to the internals of the class. This is certainly not what I would call breaking encapsulation. Actually I don't see the problem here at all.
Whether a function needs access to the internals of a class depends on the implementation, no?
No, only the interface. For instance:
class IComplex
{
public:
virtual double re() const = 0;
virtual double im() const = 0;
virtual ~IComplex() {}
};
double mod(IComplex const &c)
{
return c.re()*c.re() + c.im()*c.im();
}
I can tell that mod does not require access to the internals from the
interface alone. Of course I can't tell if IComplex::re() or IComplex::im()
actually require access to any internals (they might just generate random
numbers for instance). We can only say that these functions have access to
the internal representation which makes them dangerous -- in a bad
implementation they might break invariants promised by the class
documentation in a way mod could never do.
A maybe interesting example is a class with two methods, each of which can be implemented in terms of the other; thus, which you make access the class internals is a matter of choice. If you make one a member function and one a non-member, you're exposing this choice in the interface, which sounds like breaking encapsulation to me. Certainly, if you later decide to change your implementation (perhaps implementing function A in terms of function B turns out to be more efficient than the other way round), making one a member and the other a non-member will cause you problems.
Victor Bazarov wrote: Tom Widmer wrote:If you add functionality to a class via (non-friend) non-members, then that functionality necessarily only depends on the public interface of the class.
Yes, and?... Where is the "breaking" part? If the functionality is instead actually _part_ of public interface, what's broken? Or is adding to a class' interface in fact "breaking" some fragile "encapsulation"?
What is the essential difference between
class A { // some interface, public or otherwise };
void foo(A& a) { // some implemenation }
and
class A { // some interface, public or otherwise static void foo(A& a) { // same implemenation as above } };
What is broken in the second case compared to the first one?
The number of bits of code that need to be checked when the
implementation of A changes.
Tom
Tom Widmer wrote: Victor Bazarov wrote: Tom Widmer wrote: If you add functionality to a class via (non-friend) non-members, then that functionality necessarily only depends on the public interface of the class.
Yes, and?... Where is the "breaking" part? If the functionality is instead actually _part_ of public interface, what's broken? Or is adding to a class' interface in fact "breaking" some fragile "encapsulation"? What is the essential difference between
class A { // some interface, public or otherwise };
void foo(A& a) { // some implemenation }
and
class A { // some interface, public or otherwise static void foo(A& a) { // same implemenation as above } };
What is broken in the second case compared to the first one?
The number of bits of code that need to be checked when the implementation of A changes.
Please elaborate. Thanks.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
In article <e2**********@news.datemas.de>,
"Victor Bazarov" <v.********@comAcast.net> wrote: Cy Edmunds wrote: "Victor Bazarov" <v.********@comAcast.net> wrote in message class A { // some interface, public or otherwise };
void foo(A& a) { // some implemenation }
and
class A { // some interface, public or otherwise static void foo(A& a) { // same implemenation as above } };
What is broken in the second case compared to the first one?
V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask
In the second case a mistake in the implementation of foo can result in violation of invariants of the class.
Yes, I agree. Is that the whole thing or there's something else?
If that's the whole thing, then in my book the benefits of limiting the scope of functionality outweigh the benefits of preventing my potential mistakes while implementing 'foo'. *I* do not make any. The users of my classes OTOH do. And they make mistakes mostly because of an unclear intentions, communicated poorly by placing functionality in overly broad scopes.
How exactly have you changed the scope of foo by putting it in the class
rather than in out of it? I missed that part. Seems to me that in both
examples, the scope of foo is the same, only the name has changed.
Daniel T. wrote: [..] Seems to me [..]
Sorry, I'm bailing out. I got bored by this nonsense.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
In article <e2**********@news.datemas.de>,
"Victor Bazarov" <v.********@comAcast.net> wrote: Daniel T. wrote: [..] Seems to me [..]
Sorry, I'm bailing out. I got bored by this nonsense.
I'm not saying your wrong Victor, I'm just trying to figure out why you
are so sure you are right...
Please, explain to me how making a function a public static member of a
class gives it a smaller scope than one that is free standing.
Daniel T. wrote: In article <e2**********@news.datemas.de>, "Victor Bazarov" <v.********@comAcast.net> wrote:
Daniel T. wrote: [..] Seems to me [..]
Sorry, I'm bailing out. I got bored by this nonsense.
I'm not saying your wrong Victor, I'm just trying to figure out why you are so sure you are right...
Please, explain to me how making a function a public static member of a class gives it a smaller scope than one that is free standing.
I don't understand the question, probably. The scope of a member function
is the class of which it's the member. That's smaller than the enclosing
[namespace or other type] scope. I thought that was obvious.
Anyway, I am marking this thread "ignore". Trick me into participating in
a thread from which I bailed out, shame on you. Trick me twice...
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
"utab" <um********@gmail.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com... Dear all,
Is there a clear distinction how to decide which functions to be members of a class and which not
How is your attitude (Your general way from your experiences ...)
"If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
Thx to you all.
Here is what Scott Meyers has to say: http://www.ddj.com/dept/cpp/184401197
Victor Bazarov wrote: Tom Widmer wrote: class A { // some interface, public or otherwise };
void foo(A& a) { // some implemenation }
and
class A { // some interface, public or otherwise static void foo(A& a) { // same implemenation as above } };
What is broken in the second case compared to the first one?
The number of bits of code that need to be checked when the implementation of A changes.
Please elaborate. Thanks.
Specifically, foo needs to be checked only in case 2 if the
implementation of A later changes. In case 1, the amount of code that
may depend on the implementation of A (and must be examined to determine
this) is less.
Tom
In article <e2**********@news.datemas.de>,
"Victor Bazarov" <v.********@comAcast.net> wrote: The scope of a member function is the class of which it's the member. That's smaller than the enclosing [namespace or other type] scope. I thought that was obvious.
I thought the "scope" of a variable or function had something to do with
where it can be used in the program. Am I wrong?
In the following code:
class Foo {
public:
static int bar();
};
int bar();
does "Foo::bar()" have a smaller scope than "bar()" or not? If it does,
what does "scope" mean?
Victor says that Foo::bar() has a smaller scope and I tend to respect
his opinion (if not his somewhat abrasive demeanor.)
Daniel T. wrote: In article <e2**********@news.datemas.de>, "Victor Bazarov" <v.********@comAcast.net> wrote:
The scope of a member function is the class of which it's the member. That's smaller than the enclosing [namespace or other type] scope. I thought that was obvious.
I thought the "scope" of a variable or function had something to do with where it can be used in the program. Am I wrong?
Yes. In the following code:
class Foo { public: static int bar(); };
int bar();
does "Foo::bar()" have a smaller scope than "bar()" or not? If it does, what does "scope" mean?
The scope is the declarative region of the program in which the name (in
unqualified form, importantly) is valid.
Victor says that Foo::bar() has a smaller scope and I tend to respect his opinion (if not his somewhat abrasive demeanor.)
Victor is right here, but his abrasive demeanor is often used to
disguise ignorance or mistakes. He's not reading anyway apparently. ;)
In this case he appears to want to put the function into class scope to
avoid name clashes. However, an alternative (and more flexible) way of
doing this is to use namespaces.
Tom
Daniel T. wrote: In the following code:
class Foo { public: static int bar(); };
int bar();
does "Foo::bar()" have a smaller scope than "bar()" or not? If it does, what does "scope" mean?
Victor says that Foo::bar() has a smaller scope and I tend to respect his opinion (if not his somewhat abrasive demeanor.)
If one scope is contained entirely within another, then it can be said
to be smaller. For other cases, you need to develop some notion of
scope size. Even if there is containment, you could argue that any
shadowed pieces of the outer scope do not contribute to its size, thus
casting doubt on the validity of using containment to determine
relative size.
The scope of the name of the non-member function bar extends from its
point of declaration to the end of the translation unit. (That scope
may be interrupted in places by shadowing definitions of bar).
The scope of Foo::bar() is the class scope of Foo. Within a translation
unit, that scope is the class definition, and also the bodies of any
subsequent member function definitions.
In the above example, the Foo class declaration is placed in a region
of program text where the file scope bar() isn't visible yet. The two
scopes do not overlap, and we cannot say which is larger.
Tom Widmer wrote: In this case he appears to want to put the function into class scope to avoid name clashes. However, an alternative (and more flexible) way of doing this is to use namespaces.
Is it in fact true that an alternative is namespaces? I think Victor's
point was that putting it in a class makes it so it can't be
automatically resolved. I am not completely sure when and where
functions can be pulled out of namespace scope into the current scope
but I do know there are cases when this can occur (One of the red books
explains in some detail). I don't believe this can happen if the
function is a static class member.
Noah Roberts wrote: Tom Widmer wrote:
In this case he appears to want to put the function into class scope to avoid name clashes. However, an alternative (and more flexible) way of doing this is to use namespaces.
Is it in fact true that an alternative is namespaces? I think Victor's point was that putting it in a class makes it so it can't be automatically resolved. I am not completely sure when and where functions can be pulled out of namespace scope into the current scope but I do know there are cases when this can occur (One of the red books explains in some detail). I don't believe this can happen if the function is a static class member.
Yes, ADL allows unqualified names from other namespaces to be considered
in function calls. But you can qualify function calls to prevent this.
Quite a common practice is to use quite small namespaces (in contrast to
the monolithic namespace std), that only contain a class and its related
functions.
Anyway, I disagree with Victor on this. If one adds every little
function as an extra static member of a class, one ends up with reams of
code that need to be checked and possibly changed when you change the
implementation. Imagine, for example, a string class. Imagine that you
have lots of utility string operations, and these are all static (and
non-static) members of the string class (since they operate on strings,
that's where Victor things they should be). Now think about the job
involved in changing the string class to use reference counting, or SSO
- which of those utility methods needs changing? Some? All? You have to
check each of them in any case - this could mean checking and possibly
reimplementing 50 utility functions. Compare to the alternative, where
the string interface is minimal and complete, and the utility functions
are separate, namespace scope, non-friend functions. None of them needs
to be modified for the change of implementation.
Tom
Tom Widmer wrote: Noah Roberts wrote: Tom Widmer wrote:
In this case he appears to want to put the function into class scope to avoid name clashes. However, an alternative (and more flexible) way of doing this is to use namespaces.
Is it in fact true that an alternative is namespaces? I think Victor's point was that putting it in a class makes it so it can't be automatically resolved. I am not completely sure when and where functions can be pulled out of namespace scope into the current scope but I do know there are cases when this can occur (One of the red books explains in some detail). I don't believe this can happen if the function is a static class member.
Yes, ADL allows unqualified names from other namespaces to be considered in function calls. But you can qualify function calls to prevent this. Quite a common practice is to use quite small namespaces (in contrast to the monolithic namespace std), that only contain a class and its related functions.
Here is an example of ADL pulling in unqualified names from namespaces
so namespace scope is quite vulnerable if not coded carefully,
namespace n1{
struct S {};
void foo(S) {}
}
void bar(){
n1::S s;
foo(s);
}
In article <e2**********@emma.aioe.org>,
Tom Widmer <to********@hotmail.com> wrote: Daniel T. wrote: In article <e2**********@news.datemas.de>, "Victor Bazarov" <v.********@comAcast.net> wrote:
The scope of a member function is the class of which it's the member. That's smaller than the enclosing [namespace or other type] scope. I thought that was obvious.
I thought the "scope" of a variable or function had something to do with where it can be used in the program. Am I wrong?
Yes.
In the following code:
class Foo { public: static int bar(); };
int bar();
does "Foo::bar()" have a smaller scope than "bar()" or not? If it does, what does "scope" mean?
The scope is the declarative region of the program in which the name (in unqualified form, importantly) is valid.
Thank you for the explanation. Previously, I was of the opinion that
visibility defined scope, and the only thing that making 'func()' a
public static member (or a member of a namespace for that matter) got
you was a mangled name so it was less likely to be called in incorrect
contexts.
Hopefully, I will not confuse scope and visibility again. :-)
Daniel T. wrote: In article <e2**********@emma.aioe.org>, Tom Widmer <to********@hotmail.com> wrote:
Daniel T. wrote: In article <e2**********@news.datemas.de>, "Victor Bazarov" <v.********@comAcast.net> wrote:
>The scope of a member function >is the class of which it's the member. That's smaller than the enclosing >[namespace or other type] scope. I thought that was obvious.
I thought the "scope" of a variable or function had something to do with where it can be used in the program. Am I wrong?
Yes.
In the following code:
class Foo { public: static int bar(); };
int bar();
does "Foo::bar()" have a smaller scope than "bar()" or not? If it does, what does "scope" mean?
The scope is the declarative region of the program in which the name (in unqualified form, importantly) is valid.
Thank you for the explanation. Previously, I was of the opinion that visibility defined scope, and the only thing that making 'func()' a public static member (or a member of a namespace for that matter) got you was a mangled name so it was less likely to be called in incorrect contexts.
Hopefully, I will not confuse scope and visibility again. :-)
If I understand correctly, names in one scope may or may not be visible
in another scope. The rules that define visibility crosses but not
coincide with rules that define scoping.
utab wrote: Dear all,
Is there a clear distinction how to decide which functions to be members of a class and which not
How is your attitude (Your general way from your experiences ...)
"If the function changes the state of the object, it ought to be a member of that object." Reference Accelerated C++, A. Koenig, page 159.
Having a small, sensible, significant set of member functions. Other
functions should be non-member.
I like to think that the public interface, as defined in the class
definition, is the "mathematical definition of the object class".
Member functions have access to internal details of the class.
The encapsulation is here, in order to have the smallest number of
functions accessing a particular implementation detail.
I think that these two Herb Sutter's articles are revelant here: http://www.gotw.ca/publications/mill02.htm http://www.gotw.ca/gotw/084.htm This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: lothar |
last post by:
re:
4.2.1 Regular Expression Syntax
http://docs.python.org/lib/re-syntax.html
*?, +?, ??
Adding "?" after the qualifier makes it perform the...
|
by: klaus triendl |
last post by:
hi,
recently i discovered a memory leak in our code; after some investigation i
could reduce it to the following problem:
return objects of...
|
by: Mario |
last post by:
Hello,
I couldn't find a solution to the following problem (tried
google and dejanews), maybe I'm using the wrong keywords?
Is there a way to...
|
by: Yves Glodt |
last post by:
Hello,
if I do this:
for row in sqlsth:
________pkcolumns.append(row.strip())
________etc
without a prior:
|
by: Adrian Herscu |
last post by:
Hi all,
In which circumstances it is appropriate to declare methods as non-virtual?
Thanx,
Adrian.
|
by: Steve - DND |
last post by:
We're currently doing some tests to determine the performance of static vs
non-static functions, and we're coming up with some odd(in our opinion)...
|
by: Bern McCarty |
last post by:
Is it at all possible to leverage mixed-mode assemblies from AppDomains
other than the default AppDomain? Is there any means at all of doing this?...
|
by: amitvps |
last post by:
Secure Socket Layer is very important and useful for any web application but it brings some problems too with itself. Handling navigation between...
|
by: =?UTF-8?B?Ik1hcnRpbiB2LiBMw7Z3aXMi?= |
last post by:
PEP 1 specifies that PEP authors need to collect feedback from the
community. As the author of PEP 3131, I'd like to encourage comments
to the PEP...
|
by: puzzlecracker |
last post by:
is it even possible or/and there is a better alternative to accept
input in a nonblocking manner?
|
by: teenabhardwaj |
last post by:
How would one discover a valid source for learning news, comfort, and help for engineering designs? Covering through piles of books takes a lot of...
|
by: Kemmylinns12 |
last post by:
Blockchain technology has emerged as a transformative force in the business world, offering unprecedented opportunities for innovation and...
|
by: antdb |
last post by:
Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine
In the overall architecture, a new "hyper-convergence" concept was...
|
by: Matthew3360 |
last post by:
Hi, I have a python app that i want to be able to get variables from a php page on my webserver. My python app is on my computer. How would I make it...
|
by: AndyPSV |
last post by:
HOW CAN I CREATE AN AI with an .executable file that would suck all files in the folder and on my computerHOW CAN I CREATE AN AI with an .executable...
|
by: Arjunsri |
last post by:
I have a Redshift database that I need to use as an import data source. I have configured the DSN connection using the server, port, database, and...
|
by: WisdomUfot |
last post by:
It's an interesting question you've got about how Gmail hides the HTTP referrer when a link in an email is clicked. While I don't have the specific...
|
by: Matthew3360 |
last post by:
Hi,
I have been trying to connect to a local host using php curl. But I am finding it hard to do this. I am doing the curl get request from my web...
|
by: Oralloy |
last post by:
Hello Folks,
I am trying to hook up a CPU which I designed using SystemC to I/O pins on an FPGA.
My problem (spelled failure) is with the...
| |