Gigantic Class

I

Immortal Nephi

I consider to use either object-based programming or object-oriental
programming. I am not sure to choose the correct programming
paradigms. I start with object-based programming because I need
encapsulation.
I provide client the interface. The client uses it to define object
in main() function body. They invoke object’s public member
functions. The object’s public member functions do the job to process
algorithm. All private member functions and implementation details
are hidden.
The base class is growing too big because I add more private member
functions. I debug and test them to be working properly. They are
less reusability. You will say that gigantic class is bad practice.
Why do you think that gigantic class is truly necessary?
I get quote from The ANSI / ISO C++ Professional Programmer’s
Handbook.

Gigantic class

There are no standardized methods for measuring the size of a class.
However, many small specialized classes are preferred to a bulky
single class that contains hundreds of member functions and data
members. But bulky classes do get written. Class std::string has a
fat interface of more than 100 member functions; clearly this is an
exception to the rule and, to be honest, many people consider this to
be a compromise between conflicting design approaches. Still,
ordinary programs rarely use all these members. More than once, I’ve
seen programmers extending a class with additional member functions
and data members instead of using more plausible object-oriental
techniques such as subclassing. As a rule, a class that extends a
20-30 member function count is suspicious.
Gigantic classes are problematic for at least three reasons: users of
such classes rarely know how to use them properly, the implementation
and interface of such classes tend to undergo extensive changes and
bug-fixes; and they are not good candidates for reuse because the fat
interface and intricate implementation details can fit rarely only a
very limited usage. In a sense, large classes are very similar to
large functions.—they are noncohesive and difficult to maintain.

[end of quote]


How do you solve to divide into hundreds of subclasses from one giant
class? Inheritance is the answer, but you write derive class to use
**some** or **all** inherited member functions. You don’t want client
to use all inherited member functions. They only need to derive class
through private inheritance.

For example:

class A
{
public:
A() : a( 1 ), b( 2 ) {}
~A() {}

protected:
int a;
int b;
};

class B : public A
{
public:
B() : c( 3 ), d( 4 ) {}
~B() {}

protected:
int c;
int d;
};

class C : public B
{
public:
C() : e( 5 ), f( 6 ) {}
~C() {}

protected:
int e;
int f;
};

class D : private C
{
public:
D() : g( 7 ), h( 8 ) {}
~D() {}
void Run()
{
a += 100;
b += 200;
c += 300;
d += 400;
e += 500;
f += 600;
g += 700;
h += 800;
}

protected:
int g;
int h;
};

class E : public D
{
public:
E() : i( 9 ), j( 10 ) {}
~E() {}
void Run()
{
D::Run();
i = 900;
j = 1000;
}

private:
int i;
int j;
};

int main()
{
E e; // object e is the interface
e.Run(); // Run() is available to client.
Return 0;
}

Do you see private inheritance? All data members and member
functions are inherited down to class C and all of them are
inaccessible in class D. All data members and member functions are
inherited down to class E from class D.
The client can use only class D’s data members and member functions
that are already inherited in class E.
My example above is object-based programming. All data members and
member functions are grouped in only one big class through
inheritance.
What if you are going to say? Use object-oriental programming
instead? Base class is the general and all derived classes are
specialized.
For example, base class is the CPU’s **ALL** instruction sets. It
has internal registers as data members and pure virtual member
function Dispatch(). Each derived class have specialized instruction
sets and Dispatch() implementation.
Why should each derived class be instanstized and data members are
inherited from base class? You only need one instance like I
described that giant class has one instance.
 
B

Bo Persson

Immortal said:
I consider to use either object-based programming or object-oriental
programming. I am not sure to choose the correct programming
paradigms. I start with object-based programming because I need
encapsulation.
I provide client the interface. The client uses it to define object
in main() function body. They invoke object’s public member
functions. The object’s public member functions do the job to
process algorithm. All private member functions and implementation
details are hidden.
The base class is growing too big because I add more private member
functions. I debug and test them to be working properly. They are
less reusability. You will say that gigantic class is bad practice.
Why do you think that gigantic class is truly necessary?
I get quote from The ANSI / ISO C++ Professional Programmer’s
Handbook.

Gigantic class

There are no standardized methods for measuring the size of a class.
However, many small specialized classes are preferred to a bulky
single class that contains hundreds of member functions and data
members. But bulky classes do get written. Class std::string has a
fat interface of more than 100 member functions; clearly this is an
exception to the rule and, to be honest, many people consider this
to be a compromise between conflicting design approaches. Still,
ordinary programs rarely use all these members. More than once,
I’ve seen programmers extending a class with additional member
functions and data members instead of using more plausible
object-oriental techniques such as subclassing. As a rule, a class
that extends a 20-30 member function count is suspicious.
Gigantic classes are problematic for at least three reasons: users
of such classes rarely know how to use them properly, the
implementation and interface of such classes tend to undergo
extensive changes and bug-fixes; and they are not good candidates
for reuse because the fat interface and intricate implementation
details can fit rarely only a very limited usage. In a sense,
large classes are very similar to large functions.—they are
noncohesive and difficult to maintain.

[end of quote]


How do you solve to divide into hundreds of subclasses from one
giant class? Inheritance is the answer, but you write derive class
to use **some** or **all** inherited member functions. You don’t
want client to use all inherited member functions. They only need
to derive class through private inheritance.

For example:

class A
{
public:
A() : a( 1 ), b( 2 ) {}
~A() {}

protected:
int a;
int b;
};

class B : public A
{
public:
B() : c( 3 ), d( 4 ) {}
~B() {}

protected:
int c;
int d;
};

class C : public B
{
public:
C() : e( 5 ), f( 6 ) {}
~C() {}

protected:
int e;
int f;
};

class D : private C
{
public:
D() : g( 7 ), h( 8 ) {}
~D() {}
void Run()
{
a += 100;
b += 200;
c += 300;
d += 400;
e += 500;
f += 600;
g += 700;
h += 800;
}

protected:
int g;
int h;
};

class E : public D
{
public:
E() : i( 9 ), j( 10 ) {}
~E() {}
void Run()
{
D::Run();
i = 900;
j = 1000;
}

private:
int i;
int j;
};

int main()
{
E e; // object e is the interface
e.Run(); // Run() is available to client.
Return 0;
}

It is hard to reason about classes named A, B, and C, because that
makes it very abstract. A real class hierarchy usually is a model of
"something", where the structure of "something" often helps in
designing the model.

Most often it helps if a class does one thing, and one thing only. It
should do its "thing", and possibly maintain an internal state that it
might need (an invariant). Having protected data members breaks this,
as the class can no longer take responsibility for its own state.
Therefore protected data is very rarely used.

Unlike Java, in C++ there is generally no requirement for a single
base class. Using templates, all classes conforming to an interface
can be used as arguments to a function.


Bo Persson
 
S

Stefan Ram

Immortal Nephi said:
However, many small specialized classes are preferred to a bulky

Such metrics look superficial to me. For example, when the
specialized classes are very similar to each other, they
should be combined into a slightly larger but more general
class (DRY). It always depends also on other factors then
just the size in isolation.
members. But bulky classes do get written. Class std::string has a

Yes, yes! Go ahead and write it! It is never a mistake to
write a huge bulky class. It is only a mistake to stop there
and not refactor it. Usually, /after/ the bulky class has been
written one sees oportunities to split it or to extract classes
from it, thus it gets smaller, usually. And in the 0,1 % of all
cases, when there is no reasonable refactor to make it smaller,
it really needs to be that big. Usually, »god class« is an anti-
pattern, but under rare circumstances it might become a pattern.

A typical cell size is 10 µm, but the ostrich egg cell is
15 centimetres (5.9 in) long, 13 centimetres (5.1 in) wide,
and weighs 1.4 kilograms (3.1 lb).
class? Inheritance is the answer, but you write derive class to use

This is just one answer. And also seen to be an anti-pattern by
some (as implementation inheritance - not interface inheritance).

You need to know several refactors and apply each of them when
appropriate. There are several refactors that will reduce the
size of a class.
 
I

Immortal Nephi

Immortal said:
I consider to use either object-based programming or object-oriental
programming.  I am not sure to choose the correct programming
paradigms.  I start with object-based programming because I need
encapsulation.
I provide client the interface.  The client uses it to define object
in main() function body.  They invoke object s public member
functions.  The object s public member functions do the job to
process algorithm.  All private member functions and implementation
details are hidden.
The base class is growing too big because I add more private member
functions.  I debug and test them to be working properly.  They are
less reusability.  You will say that gigantic class is bad practice.
Why do you think that gigantic class is truly necessary?
I get quote from The ANSI / ISO C++ Professional Programmer s
Handbook.
Gigantic class
There are no standardized methods for measuring the size of a class.
However, many small specialized classes are preferred to a bulky
single class that contains hundreds of member functions and data
members.  But bulky classes do get written.  Class std::string has a
fat interface of more than 100 member functions; clearly this is an
exception to the rule and, to be honest, many people consider this
to be a compromise between conflicting design approaches.  Still,
ordinary programs rarely use all these members.  More than once,
I ve seen programmers extending a class with additional member
functions and data members instead of using more plausible
object-oriental techniques such as subclassing.  As a rule, a class
that extends a 20-30 member function count is suspicious.
Gigantic classes are problematic for at least three reasons: users
of such classes rarely know how to use them properly, the
implementation and interface of such classes tend to undergo
extensive changes and bug-fixes; and they are not good candidates
for reuse because the fat interface and intricate implementation
details can fit rarely only a very limited usage.  In a sense,
large classes are very similar to large functions. they are
noncohesive and difficult to maintain.
[end of quote]
How do you solve to divide into hundreds of subclasses from one
giant class?  Inheritance is the answer, but you write derive class
to use **some** or **all** inherited member functions.  You don t
want client to use all inherited member functions.  They only need
to derive class through private inheritance.
For example:
class A
{
public:
A() : a( 1 ), b( 2 ) {}
~A() {}
protected:
int a;
int b;
};
class B : public A
{
public:
B() : c( 3 ), d( 4 ) {}
~B() {}
protected:
int c;
int d;
};
class C : public B
{
public:
C() : e( 5 ), f( 6 ) {}
~C() {}
protected:
int e;
int f;
};
class D : private C
{
public:
D() : g( 7 ), h( 8 ) {}
~D() {}
void Run()
{
a += 100;
b += 200;
c += 300;
d += 400;
e += 500;
f += 600;
g += 700;
h += 800;
}
protected:
int g;
int h;
};
class E : public D
{
public:
E() : i( 9 ), j( 10 ) {}
~E() {}
void Run()
{
D::Run();
i = 900;
j = 1000;
}
private:
int i;
int j;
};
int main()
{
E e; // object e is the interface
e.Run(); // Run() is available to client.
Return 0;
}

It is hard to reason about classes named A, B, and C, because that
makes it very abstract. A real class hierarchy usually is a model of
"something", where the structure of "something" often helps in
designing the model.

Class A has all responsibility to handle private data members and
private member functions. Derived class B, C, and D do not make any
senses. You have no reason to inherit class A's private data members
to class B through additional new class A's public member functions.
I am like class A designer does not want clients to use inheritance
and they only need to define and use class A in their own function
body.
Most often it helps if a class does one thing, and one thing only. It
should do its "thing", and possibly maintain an internal state that it
might need (an invariant). Having protected data members breaks this,
as the class can no longer take responsibility for its own state.
Therefore protected data is very rarely used.

I agree with you. Class A does only one thing. One thing has some
internal states. Some internal states are defined in private data
members inside class A. All private member functions maniuplate
internal states directly. Some private member functions are added in
public member functions and the client only needs to invoke public
member function.

The client is allowed to derive class from class A, but they are
denied if they attempt to inherit private data members into derived
class B because protected data is not defined.
Unlike Java, in C++ there is generally no requirement for a single
base class. Using templates, all classes conforming to an interface
can be used as arguments to a function.

Sometimes, I do not need to add templates to class A. The client only
needs to use one data type such as int when they put arguments into
public member function's parameters. They can define one or more
class A objects in their function body. Also, they can use STL such
as vector. They put more class A objects in vector like five class A
objects in one array. The vector has template because class A is
defined user type.

For example:

int variable = 100;
A a1( variable );
A a2( variable + 1 );
A a3; // use default constructor as a3()
A oneArray[5];
vector < A > ( oneArray, 5 );

Make sense?
 
I

Immortal Nephi

  Such metrics look superficial to me. For example, when the
  specialized classes are very similar to each other, they
  should be combined into a slightly larger but more general
  class (DRY). It always depends also on other factors then
  just the size in isolation.


  Yes, yes! Go ahead and write it! It is never a mistake to
  write a huge bulky class. It is only a mistake to stop there
  and not refactor it. Usually, /after/ the bulky class has been
  written one sees oportunities to split it or to extract classes
  from it, thus it gets smaller, usually. And in the 0,1 % of all
  cases, when there is no reasonable refactor to make it smaller,
  it really needs to be that big. Usually, »god class« is an anti-
  pattern, but under rare circumstances it might become a pattern.

"god class"? Are you referring that giant class A is perfect with
free bugs unless you have already debugged and tested and it is to be
working properly?
  A typical cell size is 10 µm, but the ostrich egg cell is
  15 centimetres (5.9 in) long, 13 centimetres (5.1 in) wide,
  and weighs 1.4 kilograms (3.1 lb).


  This is just one answer. And also seen to be an anti-pattern by
  some (as implementation inheritance - not interface inheritance).

If inheritance is not the answer because protected data members and
protected member functions are not defined, what is the solution? You
might say that composition is the answer. Create hundreds of base
subclasses. Put them into one base main class. How can base
subclasses access base main class' private data members?

I showed you my example as class A, B, C, and D through public
inheritance above. Convert from inheritance to composition. Let's
say for example. class B, C, and D are considered to be base
subclasses and class A is considered to be base main class. Class B,
C, D can't access class A's private data members unless you add friend
class B, C, and D in class A. Class A needs to access class class B,
C, and D's member functions before class B, C, D's member functions in
turn to access class A's private data members directly.

class B { public: /* member functions access A's private data members
*/ };
class C { public: /* member functions access A's private data members
*/ };
class D { public: /* member functions access A's private data members
*/ };
class A
{
friend class B
friend class C
friend class D
public: /* member functions access class B, C, D's member functions */

private: /* private internal states as data members */
B b;
C c;
D d;
};

Class A's data members are always undefined because class A body is
not declared in the top before class B, C, and D are defined. I guess
that composition is not the answer. How do you have the solution?
 
S

Stefan Ram

Immortal Nephi said:
How do you have the solution?

To give a solution, I would need to have a problem.

A problem is a description of the required (functional and
possibly non-functional) properties of a program, that is,
of its behavior. Then, I might find an implementation.

Refactoring can only work this way, because it changes the
source code, while leaving the behavior as specified.
If there is no behavior specification, one can not do refactoring.

(Of course, I cannot promise to solve every problem posted to
Usenet, I just might try and do it for some small problems
if I have some leisure.)

The meaning of »god class« can be looked up using a search
engine.
 
I

Immortal Nephi

  To give a solution, I would need to have a problem.

  A problem is a description of the required (functional and
  possibly non-functional) properties of a program, that is,
  of its behavior. Then, I might find an implementation.

  Refactoring can only work this way, because it changes the
  source code, while leaving the behavior as specified.
  If there is no behavior specification, one can not do refactoring.

You refer "Refactoring". Do you mean divide one big problem is
divided into several small problems? I showed quote from ANSI/ISO
book above. Gigantic class is like a big function body. You create
one thing. One thing is one problem. You can't solve it at once.
You need to write small sub-functions and focus small problems. All
sub-functions are debugged and tested correctly before you put them
together in one main function.

If a bug is found, it will *affect* some or all sub-functions. Trace
every sub-functions until you found a bug. Fix one sub-function
before all sub-functions in one main function are working and running
correctly. All sub-functions do not need to be modified.
  (Of course, I cannot promise to solve every problem posted to
  Usenet, I just might try and do it for some small problems
  if I have some leisure.)

  The meaning of »god class« can be looked up using a search
  engine.

I am unable to find *god class* in Google search, but I do see *God
object*. I think that you are referring "C++ Anti-Pattern Design". I
have good understanding how C++ language is written, but I probably do
not have experience to understand Pattern Design.
 
J

Jonathan Lee

You refer "Refactoring".  Do you mean divide one big problem is
divided into several small problems?

For starters he means this:

http://www.refactoring.com/catalog/index.html

and this

http://en.wikipedia.org/wiki/Code_refactoring

Use those strategies to "pull out" code from your god object into
more compact classes.
I am unable to find *god class* in Google search, but I do see *God
object*.  I think that you are referring "C++ Anti-Pattern Design".

That's right.

--Jonathan
 
I

Immortal Nephi

For starters he means this:

 http://www.refactoring.com/catalog/index.html

and this

 http://en.wikipedia.org/wiki/Code_refactoring

Use those strategies to "pull out" code from your god object into
more compact classes.


That's right.

Jonathan,

Thank you for the information. It is very new to me and I am learning
by reading reference. You provided me two websites, but I found good
website at http://sourcemaking.com. It gives you the information
about Design Pattern and Refactoring. You can click Refactoring and
you will see reference.
 
M

Michael Doubez

        I consider to use either object-based programming or object-oriental
programming.  I am not sure to choose the correct programming
paradigms.  I start with object-based programming because I need
encapsulation.
        I provide client the interface.  The client uses it to define object
in main() function body.  They invoke object’s public member
functions.  The object’s public member functions do the job to process
algorithm.  All private member functions and implementation details
are hidden.
        The base class is growing too big because I add more private member
functions.  I debug and test them to be working properly.  They are
less reusability.  You will say that gigantic class is bad practice.
Why do you think that gigantic class is truly necessary?
[snip]

You may want to lookup "One Responsibility Rule"
http://c2.com/cgi/wiki/Wiki?OneResponsibilityRule
        How do you solve to divide into hundreds of subclasses from one giant
class?  Inheritance is the answer,

Not necessarily. I mainly use composition.

From a design point of view, I try to keep inheritance for *extending*
functionality.

[snip code]
        My example above is object-based programming.

Is it ? In what sense ?
http://en.wikipedia.org/wiki/Object-based
 All data members and
member functions are grouped in only one big class through
inheritance.
        What if you are going to say?  Use object-oriental programming
instead?  Base class is the general and all derived classes are
specialized.

As you want to use it, this is not OOP. While the wording is good,
inheritance is not taken that way (see later).
        For example, base class is the CPU’s **ALL** instruction sets.  It
has internal registers as data members and pure virtual member
function Dispatch().  Each derived class have specialized instruction
sets and Dispatch() implementation.

Taking your example, in OOP, the base class would be a x86 processor
(with only x86 instruction set) while an inherited class would be a
specific class of x86 compatible processor (let's say with MMX
support).

It doesn't mean that all additional MMX functions must be represented
as a virtual function in the base class. Inheritance is 'MMX
processor' *reusing* code from 'x86 processor' and *extending* it.
        Why should each derived class be instanstized and data members are
inherited from base class?  You only need one instance like I
described that giant class has one instance.

I don't understand your point here.

I think you are trying to make a big polymorphic class, redefining the
functions for implementation and end up having to instantiate the most
derived class. If it is the case, IMO you have a design problem here.
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

io_x said:
...
i find the word "private" and "protected" not useful
like the word "const".
in my code where is the problem?

Have you ever used the words "private" and "const" ?! Do you know the
meaning of them? Do you know that using "const" can help the compiler to do
better optimizations?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAks7L1cACgkQG6NzcAXitM+ljwCeKI/Bjv3IsUL2LNjcrsf66HNF
WPUAoIsllkIjSIj0R5Egsmat0DklGj+z
=D5CL
-----END PGP SIGNATURE-----
 
M

Michael Doubez

Do you know that using "const" can help the compiler to do
better optimizations?

I suspect that in practice, there is very little optimization the
compiler can make (even if mutable field didn't exist); in most cases
it can apply optimization by itself, detecting that data is not
modified.

There could be some difference in the location of some const data.
 
P

Puppet_Sock

On Dec 26 2009, 9:53 pm, Immortal Nephi <[email protected]>
wrote:
[long question generally about how big a class should be]

The answer depends on context of your problem.

You should be solving this problem in problem space, not coding space.

By that I mean, you don't solve a problem about, to pull a name
out of the air, traffic control, by thinking about public vs
protected inheritance, or how many lines of code should be in
a class. You solve it by identifying the classes of object in
your problem space, and identifying how they behave and interact.

Then to design your objects, you think of them as exporters
of functionality and behaviour. If the object in your problem
space is big and interacts with many other objects, then it
*may* be the case you want a big object to represent it.
Or it may be you want to re-examine your problem space and
make the problem fit into an easier to understand model.

So, to pull that example back in, in traffic control you think
about objects like cars, roads, traffic signals, emergency
vehicles, etc. and so on. These will have behaviours in
the model that is used to work on the problem. You want to
make objects in your code that behave that way. Hopefully
you can manage complexity through the usual choices, like
layers and hiding information and so on.
Socks
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top