How do you implement this Python idiom in C++

A

alainpoint

Hello,

I have the need to write the equivalent of Python class methods in C++.

Chuck Allison proposes the following
(http://www.artima.com/cppsource/simple.html):
#include <iostream>
using namespace std;

// A base class that provides counting
template<class T> class Counted {
static int count;
public:
Counted() { ++count; }
Counted(const Counted<T>&) { ++count; }
~Counted() { --count; }
static int getCount() { return count; }

};

template<class T> int Counted<T>::count = 0;

// Curious class definitions
class CountedClass : public Counted<CountedClass> {};
class CountedClass2 : public Counted<CountedClass2> {};

It apparently works but in fact it doesn't:
If you derive from such a class, you get the count of the parent class,

not of the derived class.
class CountedClass3 : public CountedClass {};

int main() {
CountedClass a;
cout << CountedClass::getCount() << endl; // 1
CountedClass b;
cout << CountedClass::getCount() << endl; // 2
CountedClass3 c;
cout << CountedClass3::getCount() << endl; // 3 and should be 1
cout << CountedClass::getCount() << endl; // 3 and should be 2

}

I am no C++ expert but i guess there might be some in the Python and
C++ newsgroups.

Alain
 
J

Jon Clements

// Curious class definitions
class CountedClass : public Counted<CountedClass> {};
class CountedClass2 : public Counted<CountedClass2> {};

It apparently works but in fact it doesn't:
If you derive from such a class, you get the count of the parent class,

not of the derived class.
class CountedClass3 : public CountedClass {};

Hint: where's the template parameter gone as per the previous two
statements...

Jon.
 
P

Pierre Barbier de Reuille

Hello,

I have the need to write the equivalent of Python class methods in C++.

Chuck Allison proposes the following
(http://www.artima.com/cppsource/simple.html):
#include <iostream>
using namespace std;

// A base class that provides counting
template<class T> class Counted {
static int count;
public:
Counted() { ++count; }
Counted(const Counted<T>&) { ++count; }
~Counted() { --count; }
static int getCount() { return count; }

};

template<class T> int Counted<T>::count = 0;

// Curious class definitions
class CountedClass : public Counted<CountedClass> {};
class CountedClass2 : public Counted<CountedClass2> {};

It apparently works but in fact it doesn't:
If you derive from such a class, you get the count of the parent class,

not of the derived class.
class CountedClass3 : public CountedClass {};

int main() {
CountedClass a;
cout << CountedClass::getCount() << endl; // 1
CountedClass b;
cout << CountedClass::getCount() << endl; // 2
CountedClass3 c;
cout << CountedClass3::getCount() << endl; // 3 and should be 1
cout << CountedClass::getCount() << endl; // 3 and should be 2

}

I am no C++ expert but i guess there might be some in the Python and
C++ newsgroups.

Alain

Why don't you post the Python code you want to "translate" ? Here, I
just don't know what you want to achieve !!

Pierre
 
A

alainpoint

Jon said:
Hint: where's the template parameter gone as per the previous two
statements...

Jon.

You miss the point; i want to derive a class and inherit all properties
without worrying about those implementation details. The Python code is
much cleaner in that respect. My post is about whether it is possible
to get such a clean interface in C++

Alain
 
J

Jon Clements

You miss the point; i want to derive a class and inherit all properties
without worrying about those implementation details. The Python code is
much cleaner in that respect. My post is about whether it is possible
to get such a clean interface in C++

I was simply pointing out that your statement declaring that it didn't
work, wasn't accurate, because the code you'd used was incorrect.

Jon
 
N

Noah Roberts

I am no C++ expert but i guess there might be some in the Python and
C++ newsgroups.

Provide compilable code that exibits your problem. The technique is
sound; you must be screwing up somehow.


#include <iostream>

using namespace std;

template <typename T>
class counted
{
static int count;

public:
counted() { ++ count; }
counted(const counted<T> &) { ++ count; }
virtual ~counted() { -- count; }
static int getCount() { return count; }
};

template <typename T>
int counted<T>::count = 0;

class C1 : public counted<C1>
{
public:
C1() : counted() {}
};

class C2 : public counted<C2>
{
public:
C2() : counted() {}
};

int main(void)
{
C1 c11;
C1 c12;
C2 c2;

cout << C1::getCount() << endl;
cout << C2::getCount() << endl;

int c;
cin >> c;

return 0;
}


output is 2 and 1 as expected. Removing the constructors in the
derivatives doesn't change that fact.
 
R

Rob Williscroft

wrote in in
comp.lang.python:
#include <iostream>
using namespace std;

// A base class that provides counting
template<class T> class Counted {
static int count;
};

template<class T> int Counted<T>::count = 0;

// Curious class definitions
class CountedClass : public Counted<CountedClass> {};
class CountedClass2 : public Counted<CountedClass2> {};

It apparently works but in fact it doesn't:
If you derive from such a class, you get the count of the parent class,

You are mistaken about how it should work in the first place.
It may well be that it doesn't do what you wan't it to.

To translate the python idom into C++ you need to replace
derivation with the CRTP (*) code the author supplied.

*) CRTP = Curiosly Recuring Template Pattern
not of the derived class.
class CountedClass3 : public CountedClass {};

Don't use the above always use:

class CountedClass3 : public Counted< CountedClass3 >
{
};

Note that the "classmethod emulation" stops here, if you need
it to continue you will need to keep using the CRTP:

template < typename T = void >
class CountedClass : public Counted< CountedClass< T > >
{
};

Create instances:

CountedClass<> cc; /* T = void */

Derive (keeping the "classmethod emulation") using the CRTP:

template < typename T = void > /* So we can "Derive" again */
class CountedClass2 : public CountedClass< CountedClass2< void > >
{
};

Note that the trick works by always making the instantition of
Counted< T > you are deriving from unique, CountedClass<> has
a base class Counted< CountedClass< void > > and CountedClass2<>
has (ultimatly) a base class Counted< CountedClass2< void > >.

Ofcouse the next problem is that CRTP-derivation above isn't real
derivation, this idom translation clearly has a breaking point.

If this is more than idle curiosity I strongly suggest you post
a version of the python code you need to translate to C++.

Rob.
 
A

alainpoint

Rob said:
If this is more than idle curiosity I strongly suggest you post
a version of the python code you need to translate to C++.

For the moment this is just healthy curiosity but i will still post the
code i would like to see translated:

class Parent:
count=0
def __init__(self):
self.__class__.count +=1
@classmethod
def getcount(cls):
return cls.count

class Child(Parent):
count=0 # replace this line by a 'pass' statement if you don't want
to reinitialise the count

a=Parent()
b=Parent()
print Parent.getcount() # you get 2
c=Child()
d=Child()
e=Child()
print Child.getcount() # you get 3 (you could get 5 if you don't
reinitialise the count)

This is as simple as it can get. I just derive from Parent and i get my
proper count (added to my parent's if i wish so).
I wish i could achieve such a code purity in C++.

Alain
 
N

Noah Roberts

For the moment this is just healthy curiosity but i will still post the
code i would like to see translated:

class Parent:
count=0
def __init__(self):
self.__class__.count +=1
@classmethod
def getcount(cls):
return cls.count

class Child(Parent):
count=0 # replace this line by a 'pass' statement if you don't want
to reinitialise the count

a=Parent()
b=Parent()
print Parent.getcount() # you get 2
c=Child()
d=Child()
e=Child()
print Child.getcount() # you get 3 (you could get 5 if you don't
reinitialise the count)

What happens if you print Parent.getcount() now?
 
P

Pierre Barbier de Reuille

For the moment this is just healthy curiosity but i will still post the
code i would like to see translated:

class Parent:
count=0
def __init__(self):
self.__class__.count +=1
@classmethod
def getcount(cls):
return cls.count

class Child(Parent):
count=0 # replace this line by a 'pass' statement if you don't want
to reinitialise the count

a=Parent()
b=Parent()
print Parent.getcount() # you get 2
c=Child()
d=Child()
e=Child()
print Child.getcount() # you get 3 (you could get 5 if you don't
reinitialise the count)

This is as simple as it can get. I just derive from Parent and i get my
proper count (added to my parent's if i wish so).
I wish i could achieve such a code purity in C++.

Well, I hope you understand that this code "purity" is possible only
because of the *dynamic* lookup of the variable name ... Thus, the same
function, once compiled, will be able to determine, at runtime, where
the current variable lies ... At the same time, tries, in Python, to
achieve the count of *all* the instances of a class, meaning that you want :

a = Parent()
b = Child()
c = Parent()
d = Child()
print Child.getcount() # 2
print Parent.getcount() # 4

That time, the automatic name lookup will come in the way as you cannot
have two "count" variables accessible from the same class.
For C++ the problem is inverse, you have a way to obtain the second
thing (using templates or macro), but the first is harder.

Pierre

PS: here is my solution in C++


#include <iostream>
using namespace std;

template <class T>
struct Counted
{
Counted() { ++count; }
Counted( Counted const& ) { ++count; }
virtual ~Counted() { --count; }
static size_t getCount() { return count; }
protected:
static size_t count;
};

template <class T>
size_t Counted<T>::count = 0;

struct cA : public Counted<cA>
{
int a;
};

struct cB : public Counted<cB>, public cA
{
// Needed to be sure of which getCount is called in cB
using Counted<cB>::getCount;
};

int main()
{
cA a,b,c;
cB d,e,f;
a.a = 1;
b.a = 1;
c.a = 1;
d.a = 1;
e.a = 1;
f.a = 1;
{
cA g;
g.a = 1;
cout << "#cA = " << cA::getCount() << endl; // 7
cout << "#cB = " << cB::getCount() << endl; // 3
}
cout << "#cA = " << cA::getCount() << endl; // 6
cout << "#cB = " << cB::getCount() << endl; // 3
return 0;
}
 
A

alainpoint

Pierre said:
Well, I hope you understand that this code "purity" is possible only
because of the *dynamic* lookup of the variable name ... Thus, the same
function, once compiled, will be able to determine, at runtime, where
the current variable lies ... At the same time, tries, in Python, to
achieve the count of *all* the instances of a class, meaning that you want :

a = Parent()
b = Child()
c = Parent()
d = Child()
print Child.getcount() # 2
print Parent.getcount() # 4

That time, the automatic name lookup will come in the way as you cannot
have two "count" variables accessible from the same class.
For C++ the problem is inverse, you have a way to obtain the second
thing (using templates or macro), but the first is harder.

Pierre

PS: here is my solution in C++


#include <iostream>
using namespace std;

template <class T>
struct Counted
{
Counted() { ++count; }
Counted( Counted const& ) { ++count; }
virtual ~Counted() { --count; }
static size_t getCount() { return count; }
protected:
static size_t count;
};

template <class T>
size_t Counted<T>::count = 0;

struct cA : public Counted<cA>
{
int a;
};

struct cB : public Counted<cB>, public cA
{
// Needed to be sure of which getCount is called in cB
using Counted<cB>::getCount;
};

int main()
{
cA a,b,c;
cB d,e,f;
a.a = 1;
b.a = 1;
c.a = 1;
d.a = 1;
e.a = 1;
f.a = 1;
{
cA g;
g.a = 1;
cout << "#cA = " << cA::getCount() << endl; // 7
cout << "#cB = " << cB::getCount() << endl; // 3
}
cout << "#cA = " << cA::getCount() << endl; // 6
cout << "#cB = " << cB::getCount() << endl; // 3
return 0;
}

I thank you for your response. The equivalent of your solution is
posted hereunder:
class cA(object):
count=0
def __init__(self):
self.__class__.count +=1
@classmethod
def getcount(cls):
return cls.count
def __del__(self):
self.__class__.count -=1
class cB(cA):
count=0
def __init__(self):
super(cB,self).__init__()
for klass in self.__class__.__bases__:
klass.count +=1

a=cA() ; b=cA(); c= cA()
d=cB() ; e=cB(); f= cB()
a.a=1;b.a=1;c.a=1;d.a=1;e.a=1;f.a=1
g=cA()
g.a=1
print '#cA=',cA.getcount() # 7
print '#cB=',cB.getcount() # 3
del g
print '#cA=',cA.getcount() # 6
print '#cB=',cB.getcount() # 3

There is nothing impossible in Python ;-)

Alain
 
P

Pierre Barbier de Reuille

Pierre Barbier de Reuille wrote: [...]

I thank you for your response. The equivalent of your solution is
posted hereunder:
class cA(object):
count=0
def __init__(self):
self.__class__.count +=1
@classmethod
def getcount(cls):
return cls.count
def __del__(self):
self.__class__.count -=1
class cB(cA):
count=0
def __init__(self):
super(cB,self).__init__()
for klass in self.__class__.__bases__:
klass.count +=1

a=cA() ; b=cA(); c= cA()
d=cB() ; e=cB(); f= cB()
a.a=1;b.a=1;c.a=1;d.a=1;e.a=1;f.a=1
g=cA()
g.a=1
print '#cA=',cA.getcount() # 7
print '#cB=',cB.getcount() # 3
del g
print '#cA=',cA.getcount() # 6
print '#cB=',cB.getcount() # 3

There is nothing impossible in Python ;-)

Alain

Well, nothing is impossible, but it is now much much more complex ! As a
proof of that, your version does not work completely :p (try deleting d
for example).

I add a working version, but you will also notice that I have to
*explicitly* walk over all the classes of the hierarchy, testing for the
one who have a "count" attribute, hoping that this attribute is indeed
for counting the number of objects and not anything else ... so the
solution is quite fragile and very slow.

class cA(object):
count=0
def __init__(self):
self.__class__.count +=1
for klass in self.__class__.__bases__:
if hasattr( klass, "count" ):
klass.count += 1

@classmethod
def getcount(cls):
return cls.count
def __del__(self):
self.__class__.count -=1
for klass in self.__class__.__bases__:
if hasattr( klass, "count" ):
klass.count -= 1
class cB(cA):
count=0

a=cA() ; b=cA(); c= cA()
d=cB() ; e=cB(); f= cB()
a.a=1;b.a=1;c.a=1;d.a=1;e.a=1;f.a=1
g=cA()
g.a=1
print '#cA=',cA.getcount() # 7
print '#cB=',cB.getcount() # 3
del g
del d
print '#cA=',cA.getcount() # 5
print '#cB=',cB.getcount() # 2

Pierre
 
A

alainpoint

Pierre said:
Pierre Barbier de Reuille wrote: [...]

I thank you for your response. The equivalent of your solution is
posted hereunder:
class cA(object):
count=0
def __init__(self):
self.__class__.count +=1
@classmethod
def getcount(cls):
return cls.count
def __del__(self):
self.__class__.count -=1
class cB(cA):
count=0
def __init__(self):
super(cB,self).__init__()
for klass in self.__class__.__bases__:
klass.count +=1

a=cA() ; b=cA(); c= cA()
d=cB() ; e=cB(); f= cB()
a.a=1;b.a=1;c.a=1;d.a=1;e.a=1;f.a=1
g=cA()
g.a=1
print '#cA=',cA.getcount() # 7
print '#cB=',cB.getcount() # 3
del g
print '#cA=',cA.getcount() # 6
print '#cB=',cB.getcount() # 3

There is nothing impossible in Python ;-)

Alain

Well, nothing is impossible, but it is now much much more complex ! As a
proof of that, your version does not work completely :p (try deleting d
for example).

I add a working version, but you will also notice that I have to
*explicitly* walk over all the classes of the hierarchy, testing for the
one who have a "count" attribute, hoping that this attribute is indeed
for counting the number of objects and not anything else ... so the
solution is quite fragile and very slow.

class cA(object):
count=0
def __init__(self):
self.__class__.count +=1
for klass in self.__class__.__bases__:
if hasattr( klass, "count" ):
klass.count += 1

@classmethod
def getcount(cls):
return cls.count
def __del__(self):
self.__class__.count -=1
for klass in self.__class__.__bases__:
if hasattr( klass, "count" ):
klass.count -= 1
class cB(cA):
count=0

a=cA() ; b=cA(); c= cA()
d=cB() ; e=cB(); f= cB()
a.a=1;b.a=1;c.a=1;d.a=1;e.a=1;f.a=1
g=cA()
g.a=1
print '#cA=',cA.getcount() # 7
print '#cB=',cB.getcount() # 3
del g
del d
print '#cA=',cA.getcount() # 5
print '#cB=',cB.getcount() # 2

Pierre

Good point Pierre. But you'll have to admit that the class usage in
Python is much simpler (just derive from the class)
class cB(cA):
count=0
contrarily to the C++ usage where you must remind the compiler of the
Counted class in every derived class.

In Python, you have to bite only once thru the sour apple ....


Alain
 
B

benben

You are heading the wrong way...

There are a number of ways to implement this but the easiest I can think
of is to use RTTI.

To get around with counting sub-objects you can rely on virtual
inheritance, which only happens at the top of the inheritance tree.

Here is a simple demo:

#include <iostream>
#include <typeinfo>
#include <map>

class count
{
public:
typedef std::map<const std::type_info*, unsigned int> counts_t;
static counts_t counts;

const std::type_info* ti;

static unsigned int get_count(const std::type_info& c)
{return counts[&c];}

count(const std::type_info& c):ti(&c){++counts[ti];}
~count(){--counts[ti];}
};

count::counts_t count::counts;

class c1: virtual private count
{
public: c1(): count(typeid(c1)){}
};

class c2: public c1, virtual private count
{
public: c2(): count(typeid(c2)){}
};

int main()
{
c1 t1[3];
c2 t2[5];

std::cout << count::get_count(typeid(c1)) << "\n";
<< count::get_count(typeid(c2)) << "\n";

return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top