STL: copy vector of class ?

S

sd2004

could someone please show/help me to copy all element from "class dog"
to "class new_dog" ?
Note: "class new_dog" has new element "age" which should have value
"my_age"
/////////////////////////////// source code
///////////////////////////////
#include<iostream>
#include <string>
#include<vector>
#include<sstream>
#include<fstream>
#include<numeric>
using namespace std;

class dog
{
public:
string name;
int id;
int YearBorn;
string type;
};

class new_dog
{
public:
string name;
int id;
string age;
string type;
};

#define goldenretriever 11
#define Lab 33
#define Boxer 44
#define Terrier 55
int const CurrentYear =2006;

int dog_name (const string& name,const string& type ,const int age);
int main()
{
vector<dog> v;
vector<new_dog> v2;

new_dog dog_type;
dog dog_class;

ifstream in ("test5e.txt");
string line;
while (!getline(in,line).eof()){
if (line.find("#")!=std::string::npos)continue;
istringstream is(line);
if(is>>dog_class.name>>dog_class.id>>dog_class.YearBorn>>dog_class.type)
{
v.push_back(dog_class);
}
}
vector<dog>::iterator search;
for (search=v.begin();search!=v.end();++search){
int my_age;
switch (search->id){
case goldenretriever:
my_age =dog_name(search->name,search->type,search->YearBorn);
//cout << "My dog is: "<<search->name<< " Age is :"<<
my_age<<endl;
break;
case Lab:
my_age=dog_name(search->name,search->type,search->YearBorn);
break;
case Boxer:
my_age=dog_name(search->name,search->type,search->YearBorn);
break;
case Terrier:
my_age=dog_name(search->name,search->type,search->YearBorn);
break;
default:
break;
} //switch

cout << "Dog name is: "<<search->name<< " ,Age is :"<<
my_age<<endl;


} // for loop

return 0;

}
int dog_name (const string& name,const string& type,int YearBorn){

return (CurrentYear-YearBorn);
}

/////////// input file "test5e.txt" //////////////////////////////

########################################
#Name ID YearBorn Type
########################################
Cricket 11 2000 GoldenRetriever
Nitro 11 1999 GoldenRetriever
Maxtor 33 2004 Lab
Arron 44 2001 Boxer
#Arron 44 2002 Boxer
Dora 55 2000 Terrier
 
D

Daniel T.

"sd2004 said:
could someone please show/help me to copy all element from "class dog"
to "class new_dog" ?

The short answer is, don't do that. Make a member-function in the dog
class that accepts the current year as a parameter and returns the dog's
age.

I suspect this is a homework question so I won't give you the whole
answer, but I do want to help out.

int dog::age_at( int year ) { return year - year_born; }
 
D

davidrubin

Daniel said:
The short answer is, don't do that. Make a member-function in the dog
class that accepts the current year as a parameter and returns the dog's
age.

I suspect this is a homework question so I won't give you the whole
answer, but I do want to help out.

int dog::age_at( int year ) { return year - year_born; }

It makes absolutely no sense to have such a method in the interface of
'dog'. You need a method to return the 'yearOfBirth' of the dog (set at
construction), and then you can do whatever math you want with it.
 
P

Peter_Julian

| could someone please show/help me to copy all element from "class dog"
| to "class new_dog" ?
| Note: "class new_dog" has new element "age" which should have value
| "my_age"

Since you are taking an old class and adding features, why not inherit?
Isn't new_dog still a dog? (is_a relationship). In so far as age is
concerned, shouldn't that be a member function of the new_dog class
instead of a variable that needs to be modified on a specific birthday
for each instance? Isn't age() a new feature that should be deduced
dynamically based on a current date?

class Dog
{
const std::string name;
const int id;
const int YearBorn;
const std::string type;
public:
Dog(std::string s, int n, int y, std::string t); // hint: init list
virtual ~Dog();
/* member functions */
std::string getName() const;
int getID() const;
int getYearBorn() const;
std::string getType() const;
};

class NewDog : public Dog
{
public:
NewDog(std::string s, int n, int y, std::string t) : Dog(s, n, y, t)
{ }
~NewDog() { }
/* member functions */
int getAge(const int currentyear) const
{
return currentyear - getYearBorn();
}
};

|
| class new_dog
| {
| public:
| string name;
| int id;
| string age;
| string type;
| };


| /////////////////////////////// source code
| ///////////////////////////////
| #include<iostream>
| #include <string>
| #include<vector>
| #include<sstream>
| #include<fstream>
| #include<numeric>
| using namespace std;
|
| class dog
| {
| public:
| string name;
| int id;
| int YearBorn;
| string type;
| };
|
| class new_dog
| {
| public:
| string name;
| int id;
| string age;
| string type;
| };
|
| #define goldenretriever 11
| #define Lab 33
| #define Boxer 44
| #define Terrier 55
| int const CurrentYear =2006;
|
| int dog_name (const string& name,const string& type ,const int age);
| int main()
| {
| vector<dog> v;
| vector<new_dog> v2;
|
| new_dog dog_type;
| dog dog_class;
|
| ifstream in ("test5e.txt");
| string line;
| while (!getline(in,line).eof()){
| if (line.find("#")!=std::string::npos)continue;
| istringstream is(line);
|
if(is>>dog_class.name>>dog_class.id>>dog_class.YearBorn>>dog_class.type)
| {
| v.push_back(dog_class);
| }
| }
| vector<dog>::iterator search;
| for (search=v.begin();search!=v.end();++search){
| int my_age;
| switch (search->id){
| case goldenretriever:
| my_age =dog_name(search->name,search->type,search->YearBorn);
| //cout << "My dog is: "<<search->name<< " Age is :"<<
| my_age<<endl;
| break;
| case Lab:
| my_age=dog_name(search->name,search->type,search->YearBorn);
| break;
| case Boxer:
| my_age=dog_name(search->name,search->type,search->YearBorn);
| break;
| case Terrier:
| my_age=dog_name(search->name,search->type,search->YearBorn);
| break;
| default:
| break;
| } //switch
|
| cout << "Dog name is: "<<search->name<< " ,Age is :"<<
| my_age<<endl;
|
|
| } // for loop
|
| return 0;
|
| }
| int dog_name (const string& name,const string& type,int YearBorn){
|
| return (CurrentYear-YearBorn);
| }
|
| /////////// input file "test5e.txt" //////////////////////////////
|
| ########################################
| #Name ID YearBorn Type
| ########################################
| Cricket 11 2000 GoldenRetriever
| Nitro 11 1999 GoldenRetriever
| Maxtor 33 2004 Lab
| Arron 44 2001 Boxer
| #Arron 44 2002 Boxer
| Dora 55 2000 Terrier
|
 
S

sd2004

I modified the source code as recommend by the expert as far as I
understood.
However , the compiler still give me error, could someone please help.
/////////////////// ERROR MESSAGE ////////////////////////////////

bash-2.05b$ g++ test5f.cpp
test5f.cpp: In function `int main()':
test5f.cpp:48: error: no matching function for call to
`std::vector<dog,
std::allocator<dog> >::push_back(int)'
/usr/include/c++/3.3.3/bits/stl_vector.h:596: error: candidates are:
void
std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = dog,
_Alloc =
std::allocator<dog>]
test5f.cpp:52: error: no matching function for call to
`std::vector<dog,
std::allocator<dog> >::push_back(int)'
/usr/include/c++/3.3.3/bits/stl_vector.h:596: error: candidates are:
void
std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = dog,
_Alloc =
std::allocator<dog>]
test5f.cpp:56: error: no matching function for call to
`std::vector<dog,
std::allocator<dog> >::push_back(int)'
/usr/include/c++/3.3.3/bits/stl_vector.h:596: error: candidates are:
void
std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = dog,
_Alloc =
std::allocator<dog>]
test5f.cpp:60: error: no matching function for call to
`std::vector<dog,
std::allocator<dog> >::push_back(int)'
/usr/include/c++/3.3.3/bits/stl_vector.h:596: error: candidates are:
void
std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = dog,
_Alloc =
std::allocator<dog>]
bash-2.05b$

/////////////////////////// source code //////////////////////////
#include<iostream>
#include <string>
#include<vector>
#include<sstream>
#include<fstream>
#include<numeric>
using namespace std;

class dog
{
public:
string name;
int id;
int YearBorn;
string type;
int age (const int year );
};


#define goldenretriever 11
#define Lab 33
#define Boxer 44
#define Terrier 55
int const CurrentYear =2006;

int dog_age (const string& name,const string& type ,const int age);
int main()
{
vector<dog> v;

dog dog_class;

ifstream in ("test5f.txt");
string line;
while (!getline(in,line).eof()){
if (line.find("#")!=std::string::npos)continue;
istringstream is(line);
if(is>>dog_class.name>>dog_class.id>>dog_class.YearBorn>>dog_class.type)
{
v.push_back(dog_class);
}
}
vector<dog>::iterator search;
for (search=v.begin();search!=v.end();++search){
int my_age;
switch (search->id){
case goldenretriever:
v.push_back(dog_class.age(search->YearBorn)); //line 48
//dog_class.age(search->YearBorn);
break;
case Lab:
v.push_back(dog_class.age(search->YearBorn)); //line 52
//dog_class.age(search->YearBorn);
break;
case Boxer:
v.push_back(dog_class.age(search->YearBorn)); // line 56
//dog_class.age(search->YearBorn);
break;
case Terrier:
v.push_back(dog_class.age(search->YearBorn)); // line 60
//dog_class.age(search->YearBorn);
break;
default:
break;
}

}

vector<dog>::iterator i;
for (i=v.begin();i!=v.end();++i){
//cout << "NEW Dog name: " <<i->e << " NEW Age: "<< i->age <<endl;
}
return 0;

}
int dog::age (const int year)
{
return (CurrentYear-YearBorn);
}
 
P

Peter_Julian

| I modified the source code as recommend by the expert as far as I
| understood.
| However , the compiler still give me error, could someone please help.
| /////////////////// ERROR MESSAGE ////////////////////////////////
|
| bash-2.05b$ g++ test5f.cpp
| test5f.cpp: In function `int main()':
| test5f.cpp:48: error: no matching function for call to
| `std::vector<dog,
| std::allocator<dog> >::push_back(int)'

I'm no expert but if you don't show minimum code, noone can help. You
should be pushing back the result of a NewDog ctor invocation into the
std::vector container, see main() below. ie:
dogs.push_back( NewDog("name", id, year, "type") );

I've left out the assignment operators for brevity and did not seperate
the headers and source for the same reason. Don't inject the code into
your project, learn the language instead (its worth it since very little
work is involved for considerable results). One doesn't construct a
moving car if he can't first construct one of its wheels. Run in debug
with breakpoints until you get it.

// Proj_Dog.cpp
#include <iostream>
#include <ostream>
#include <string>
#include <vector>

class Dog
{
std::string name;
int id;
int yearborn;
std::string type;
public:
/* ctor */
Dog(std::string s, int n, int y, std::string t)
: name(s), id(n), yearborn(y), type(t) { }
/* copy ctor */
Dog(const Dog& copy)
{
name = copy.name;
id = copy.id;
yearborn = copy.yearborn;
type = copy.type;
}
/* d~tor */
virtual ~Dog() { }
/* member functions */
std::string getName() const { return name; }
int getID() const { return id; }
int getYearBorn() const { return yearborn; }
std::string getType() const { return type; }
};

class NewDog : public Dog
{
public:
/* ctor */
NewDog(std::string s, int n, int y, std::string t) : Dog(s, n, y, t)
{ }
/* copy ctor */
NewDog(const NewDog& copy) : Dog(copy) { }
/* d~tor */
~NewDog() { }
/* member functions */
int getAge(const int currentyear) const
{
return currentyear - getYearBorn();
}
/* friend operators */
friend std::eek:stream& operator<<(std::eek:stream&, const NewDog&);
};

std::eek:stream& operator<<(std::eek:stream& os, const NewDog& nd)
{
os << "name:" << nd.getName();
os << " id:" << nd.getID();
os << " yearborn:" << nd.getYearBorn();
os << " type:" << nd.getType();
return os;
}

int main()
{
int id(0);
std::vector<NewDog> dogs; // our container
dogs.push_back( NewDog("dog_1", ++id, 2001, "type_1") );
dogs.push_back( NewDog("dog_2", ++id, 2002, "type_2") );
dogs.push_back( NewDog("dog_3", ++id, 2003, "type_3") );
dogs.push_back( NewDog("dog_4", ++id, 2004, "type_4") );

int year(2006); // the current year
typedef std::vector<NewDog>::iterator Iter;
Iter it = dogs.begin();
for (it; it != dogs.end(); ++it)
{
std::cout << *it;
std::cout << " age: " << (*it).getAge(year) << std::endl;
}
return 0;
}

/*
name:dog_1 id:1 yearborn:2001 type:type_1 age: 5
name:dog_2 id:2 yearborn:2002 type:type_2 age: 4
name:dog_3 id:3 yearborn:2003 type:type_3 age: 3
name:dog_4 id:4 yearborn:2004 type:type_4 age: 2
*/

obviously, the result of age is dependent on the value assigned to year.
Can you see how simple the exercise becomes once you friendify and
overload the global operator<< for a NewDog?

Now expand the NewDog class to serialize data to and from a file using
the same principle. Perhaps read(std::string& filename) and write(...)
might fit the bill.
 
D

Daniel T.

It makes absolutely no sense to have such a method in the interface of
'dog'. You need a method to return the 'yearOfBirth' of the dog (set at
construction), and then you can do whatever math you want with it.

Any algorithm that is used to determine the dog's age, should probably
also check for things like negative age, and probably also check to see
if the dog died before that year (and thus never reached that age.) In
other words, in a real program the algorithm would probably be much more
complicated that simply subtracting one number from another. Even if it
isn't, if the dog's age is needed in more than one place, "it makes
absolutely no sense" to duplicate the code required to determine the
dog's age. In that case the code should be placed in a function. Now,
where should that function be placed? The most logical place is in the
Dog class.

So yes, in any but the most simple programs, it does make sense to have
an age like function in the Dog class.
 
D

davidrubin

Daniel said:
Any algorithm that is used to determine the dog's age, should probably
also check for things like negative age, and probably also check to see
if the dog died before that year (and thus never reached that age.) In
other words, in a real program the algorithm would probably be much more
complicated that simply subtracting one number from another. Even if it
isn't, if the dog's age is needed in more than one place, "it makes
absolutely no sense" to duplicate the code required to determine the
dog's age. In that case the code should be placed in a function. Now,
where should that function be placed? The most logical place is in the
Dog class.

The proposed function is

int dog::age_at( int year ) { return year - year_born; }

This is a utility function, and belongs in something like DogUtil:

struct DogUtil {
//...

static int ageAt(const Dog& dog, int year);
// Return the non-negative age of the specified 'dog' in the
// specified 'year'. Return a negative value is 'year < 0', or
// 'year' is less than the year of birth of 'dog'.
};

A candidate member function might be

class Dog {
//...
public:
//...
int age() const;
// Return the current age of this dog.
};

Do you see the difference?
 
D

Daniel T.

The proposed function is

int dog::age_at( int year ) { return year - year_born; }

This is a utility function, and belongs in something like DogUtil:

struct DogUtil {
//...

static int ageAt(const Dog& dog, int year);
// Return the non-negative age of the specified 'dog' in the
// specified 'year'. Return a negative value is 'year < 0', or
// 'year' is less than the year of birth of 'dog'.
};

Will you agree with me that a dog's age is a piece of data that is
associated with the dog? If so, why is some other class providing that
data? And if not, why is it the *dog's* age?

What data is associated with DogUtil, or is it just a bag of functions?
A candidate member function might be

class Dog {
//...
public:
//...
int age() const;
// Return the current age of this dog.
};

The above would only work if the Dog class has a dependency on something
that can provide today's date. There's nothing wrong with that if there
are several Dog member-functions that also need to know today's date,
otherwise it is inappropriate. If this is the only member-function that
needs a date to produce the output, then it should accept the date as a
parameter.

My original proposed function has the added bonus of letting the client
determine the age of the dog at any particular year, whereas the
member-function you are proposing can only tell the "current age" of the
dog.
 
K

Kai-Uwe Bux

Daniel said:
Any algorithm that is used to determine the dog's age, should probably
also check for things like negative age, and probably also check to see
if the dog died before that year (and thus never reached that age.) In
other words, in a real program the algorithm would probably be much more
complicated that simply subtracting one number from another.
and:



Will you agree with me that a dog's age is a piece of data that is
associated with the dog? If so, why is some other class providing that
data? And if not, why is it the *dog's* age?

Your proposal means to increase the number of members for the dog class
without sufficient cause. The proposed member yearOfBirth() provides all
necessary information and is a primitive, in terms of which other functions
can be defined. The proposed age() member lacks that property, in
particular if it would incorporate sanity checks like making sure the
result is non-negative.

Would you also opt for a member function

bool isOlderThan ( dog const & other );

or should that be a free standing function:

bool isOlder ( dog const & a, dog const & b ;

How would you implement it in terms of age() or in terms of yearOfBirth().
Note that there is a subtle difference between

bool isOlder( dog const & a, dog const & b ) {
return( a.yearOfBirth() < b.yearOfBirth() );
}

and

bool isOlderThan( dog const & a, dog const & b ) {
return( a.age( 0 ) > b.age( 0 ) );
}

namely that a.age(0) might throw since it is likely to yield a negative
result, at least for dogs born recently. Now, which year would you pick
instead of 0? If you have age also check whether the dog died already, you
are in even more trouble.

Of course, you could have both: a yearOfBirth() member and an age() member.
But where do you stop? Are you willing to add members to the dog class each
time some other piece of code would find those handy? Freestanding
functions can be added any time without the need to change the header
dog.h. That is, why I would opt for a primitive like yearOfBirth() instead
of an age() member function.


Best

Kai-Uwe Bux
 
D

Daniel T.

Kai-Uwe Bux said:
Your proposal means to increase the number of members for the dog class
without sufficient cause. The proposed member yearOfBirth() provides all
necessary information and is a primitive, in terms of which other functions
can be defined. The proposed age() member lacks that property, in
particular if it would incorporate sanity checks like making sure the
result is non-negative.

Would you also opt for a member function

bool isOlderThan ( dog const & other );

or should that be a free standing function:

bool isOlder ( dog const & a, dog const & b ;

In this case, 'isOlder' should be a free standing function, because it
is not a property of any particular dog, but rather a comparison of two
different dogs.

Again, are you saying that a dog's age is not a property of the dog?
Of course, you could have both: a yearOfBirth() member and an age() member.
But where do you stop? Are you willing to add members to the dog class each
time some other piece of code would find those handy?

I add the member-function when there is some duplication (which tells us
that a function is a good idea) and the code is logically a property of
the class.
 
K

Kai-Uwe Bux

Daniel said:
In this case, 'isOlder' should be a free standing function, because it
is not a property of any particular dog, but rather a comparison of two
different dogs.

Again, are you saying that a dog's age is not a property of the dog?

Well, I fail to see how you maintain that age is a property whereas isOlder
is a relation:

* isOlder is a relation between two dogs, i.e., a function that
maps ordered pairs of dogs to truth-values. A signature
representing that would read:

bool isOlder ( Dog const &, Dog const & );

* age() is a function that maps an ordered pair of a dog and a year
to a number. Here the corresponding signature reads:

int age_in_year ( Dog const &, int );

From this signature it is also clear that, if you consider age as a property
of the dog, you should also (by symmetry) consider it a property of the
year. Now, if you had a Year class, would you propose a member function:

class Year {
...

int age ( Dog const & );

};

BTW: since there is no year 0 in our calendar, a Year class is less silly
than one might think.

There really is no difference: being older than my puppy is of course a
property of dogs in the same way that being 8 years old in the year 2008 is
a property of dogs. And of course, being a year in which my puppy is 12, is
a property of years.

I cannot bring myself to take "is a property of" as a valid guideline for
class design.

I add the member-function when there is some duplication (which tells us
that a function is a good idea) and the code is logically a property of
the class.

Based on the demonstrated parallelism between isOlder() and age(), I would
maintain that being "logically property of the class" is not a good
guideline. Instead, I would try to go with free-standing functions as much
as possible. Within the class, I would put the bare minimum of primitives
needed to implement the free-standing functions as non-friends.

Of course, ultimately, I probably do not follow rules but gutt feelings
about what is most appropriate in a particular case. And, I guess, it is
those gutt feelings that tell me in this case, that age() should be
free-standing and the class should have a dateOfBirth() member instead.


Best

Kai-Uwe Bux
 
D

davidrubin

Kai-Uwe Bux said:
Your proposal means to increase the number of members for the dog class
without sufficient cause. The proposed member yearOfBirth() provides all
necessary information and is a primitive, in terms of which other functions
can be defined. The proposed age() member lacks that property, in
particular if it would incorporate sanity checks like making sure the
result is non-negative.

Would you also opt for a member function

bool isOlderThan ( dog const & other );

or should that be a free standing function:

bool isOlder ( dog const & a, dog const & b ;

How would you implement it in terms of age() or in terms of yearOfBirth().
Note that there is a subtle difference between

bool isOlder( dog const & a, dog const & b ) {
return( a.yearOfBirth() < b.yearOfBirth() );
}

and

bool isOlderThan( dog const & a, dog const & b ) {
return( a.age( 0 ) > b.age( 0 ) );
}

namely that a.age(0) might throw since it is likely to yield a negative
result, at least for dogs born recently. Now, which year would you pick
instead of 0? If you have age also check whether the dog died already, you
are in even more trouble.

Of course, you could have both: a yearOfBirth() member and an age() member.
But where do you stop? Are you willing to add members to the dog class each
time some other piece of code would find those handy? Freestanding
functions can be added any time without the need to change the header
dog.h. That is, why I would opt for a primitive like yearOfBirth() instead
of an age() member function.

Just to clarify, Kai-Uwe is talking about 'int age_at(int year)', not
'const int age() const'. The names keep changing :)

If you look at the two original class definitions, one has a 'YearBorn'
member, and the other has an 'age' member (although the type is
'string'). When your class represents a value, such as the dog classes
in this thread, good practice dictates that you have accessors an
manipulators (where appropriate) corresponding to the data members of
the class, and utilities that operate on class instances. You do not
typically add methods to the class to perform some random function,
like subtract the 'YearBorn' member from a random integer.
 
D

Daniel T.

Just to clarify, Kai-Uwe is talking about 'int age_at(int year)', not
'const int age() const'. The names keep changing :)

Not just the names, but the dependencies as well. 'age' has an implicit
dependency on whatever produces the current date, 'age_at' doesn't.
If you look at the two original class definitions, one has a 'YearBorn'
member, and the other has an 'age' member (although the type is
'string').

I have nothing against a 'yearBorn' member-function, by all means put it
in as well.
When your class represents a value, such as the dog classes
in this thread, good practice dictates that you have accessors an
manipulators (where appropriate) corresponding to the data members of
the class, and utilities that operate on class instances.

Where in the world did you get that from? The Dog class is a primary
abstraction of the problem space. I have no problem with the accessors
and manipulators, until you tell me they have to be removed/changed if
the member-variable is removed/changed. That breaks encapsulation in a
big way.
You do not
typically add methods to the class to perform some random function,
like subtract the 'YearBorn' member from a random integer.

The age of the dog is certainly not a "random function", it is important
to the problem space.
 
D

Daniel T.

Again, are you saying that a dog's age is not a property of the dog?

Well, I fail to see how you maintain that age is a property whereas isOlder
is a relation:

* isOlder is a relation between two dogs, i.e., a function that
maps ordered pairs of dogs to truth-values. A signature
representing that would read:

bool isOlder ( Dog const &, Dog const & );

* age() is a function that maps an ordered pair of a dog and a year
to a number. Here the corresponding signature reads:

int age_in_year ( Dog const &, int );

From this signature it is also clear that, if you consider age as a property
of the dog, you should also (by symmetry) consider it a property of the
year. Now, if you had a Year class, would you propose a member function:

class Year {
...

int age ( Dog const & );

};[/QUOTE]

Do you really think that a dog's age is the property of the current
year? Does that make *any* sense? How often have you asked someone
which year his dog's age belongs to?
 
K

Kai-Uwe Bux

Daniel said:
Well, I fail to see how you maintain that age is a property whereas
isOlder is a relation:

* isOlder is a relation between two dogs, i.e., a function that
maps ordered pairs of dogs to truth-values. A signature
representing that would read:

bool isOlder ( Dog const &, Dog const & );

* age() is a function that maps an ordered pair of a dog and a year
to a number. Here the corresponding signature reads:

int age_in_year ( Dog const &, int );

From this signature it is also clear that, if you consider age as a
property of the dog, you should also (by symmetry) consider it a property
of the year. Now, if you had a Year class, would you propose a member
function:

class Year {
...

int age ( Dog const & );

};

Do you really think that a dog's age is the property of the current
year? Does that make *any* sense? [snip] [/QUOTE]

Well, a widely used calendar is apparently based on the assumption that the
age of Jesus Christ is a somehow significant property of a given year :)
So, what about:

class Year {

int age_of ( Entity const & default = Static_Humans::Jesus_Christ );

}


Best

Kai-Uwe Bux
 
D

davidrubin

Daniel said:
Not just the names, but the dependencies as well. 'age' has an implicit
dependency on whatever produces the current date, 'age_at' doesn't.

'age' depends on standard library functions (e.g. 'std::time', etc).
This is a perfectly reasonable dependency. However, I am not
recommending that 'age' be in the interface of 'Dog', except that if
you wanted to return the dog's age in addition to the year of birth,
returning the current age is a much more reasonable method than one
which returns the age based on a random input: current age is a
"derived" property of 'YearBorn', and requires none of the range
checking 'age_at' does.
I have nothing against a 'yearBorn' member-function, by all means put it
in as well.


Where in the world did you get that from?

Lakos '96.
The Dog class is a primary
abstraction of the problem space. I have no problem with the accessors
and manipulators, until you tell me they have to be removed/changed if
the member-variable is removed/changed. That breaks encapsulation in a
big way.


The age of the dog is certainly not a "random function", it is important
to the problem space.

There is a difference between 'age' taking no arguments, and 'age_at',
which takes a year as input. "Current age" is a property of Dog. "Age
at year X" is not; it is a function of Dog and year.
 
D

Daniel T.

Kai-Uwe Bux said:
Daniel said:
Kai-Uwe Bux said:
Again, are you saying that a dog's age is not a property of the dog?

Well, I fail to see how you maintain that age is a property whereas
isOlder is a relation:

* isOlder is a relation between two dogs, i.e., a function that
maps ordered pairs of dogs to truth-values. A signature
representing that would read:

bool isOlder ( Dog const &, Dog const & );

* age() is a function that maps an ordered pair of a dog and a year
to a number. Here the corresponding signature reads:

int age_in_year ( Dog const &, int );

From this signature it is also clear that, if you consider age as a
property of the dog, you should also (by symmetry) consider it a property
of the year. Now, if you had a Year class, would you propose a member
function:

class Year {
...

int age ( Dog const & );

};

Do you really think that a dog's age is the property of the current
year? Does that make *any* sense? [snip]

Well, a widely used calendar is apparently based on the assumption that the
age of Jesus Christ is a somehow significant property of a given year :)
So, what about:

class Year {

int age_of ( Entity const & default = Static_Humans::Jesus_Christ );

}

We are talking about a program where 'dog' is a primary abstraction,
perhaps a vet's patient database, do *you* think that
"year::age_of_Jesus_Christ" is an appropriate function of such a program?
 
K

Kai-Uwe Bux

Daniel said:
Kai-Uwe Bux said:
Daniel said:
Again, are you saying that a dog's age is not a property of the dog?

Well, I fail to see how you maintain that age is a property whereas
isOlder is a relation:

* isOlder is a relation between two dogs, i.e., a function that
maps ordered pairs of dogs to truth-values. A signature
representing that would read:

bool isOlder ( Dog const &, Dog const & );

* age() is a function that maps an ordered pair of a dog and a year
to a number. Here the corresponding signature reads:

int age_in_year ( Dog const &, int );

From this signature it is also clear that, if you consider age as a
property of the dog, you should also (by symmetry) consider it a
property of the year. Now, if you had a Year class, would you propose
a member function:

class Year {
...

int age ( Dog const & );

};

Do you really think that a dog's age is the property of the current
year? Does that make *any* sense? [snip]

Well, a widely used calendar is apparently based on the assumption that
the age of Jesus Christ is a somehow significant property of a given year
:) So, what about:

class Year {

int age_of ( Entity const & default = Static_Humans::Jesus_Christ );

}

We are talking about a program where 'dog' is a primary abstraction,
perhaps a vet's patient database, do *you* think that
"year::age_of_Jesus_Christ" is an appropriate function of such a program?

a) Please, lighten up. Did you, by any chance, miss the "this is a joke
flag"?

b) I just gave reasons why I would prefer a free standing function

int age_of_in_year ( Dog const & dog, int year );

to a member function

class Dog {

int age_in_year ( int year );

}

In that part of the argument where I tried to refute your reasoning, I
applied your criterion (namely the phrase "is a property of") in ways that
you did not forsee just to demonstrate why I would not consider it a good
guideline for class design. That's all.

DISCLAIMER: That counter-argument, of course, does not apply to any other
reasons that you may or may not have to prefer a member function to a free
standing function in this particular case.

However, the way you iterate the question

"Again, are you saying that a dog's age is not a property of the dog?"

indicates that this seems to be a very important point to you. In direct
response: I agree that age is a property of the dog; but that is completely
inconsequential for whether it should be a member function or a free
standing function.


Best

Kai-Uwe
 

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

Similar Threads

STL for loop ? 4
Another STL ? 3
STL ?? 2
passing argument in STL loop ? 3
STL ? 4
School Project 1
STL Vector Access 1
Erratic Container Behavior (list & vector) 2

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top