Concrete Classes

Hi,

I have this text from Bjarne about Concrete Classes, but I can't understand it completely especially from the part starting from "The defining characteristic of ...". Will you illustrate or explain the case in simple language, please? And, for example, what is the difference between "the definition" and "the implementation" here?


The basic idea of concrete classes is that they behave “just like built-in types.”
For example, a complex number type and an infinite-precision integer are much
like built-in int, except of course that they have their own semantics and sets of
operations. Similarly, a vector and a string are much like built-in arrays, except
that they are better behaved (§9.2, §10.3, §11.2).
The defining characteristic of a concrete type is that its representation is part
of its definition. In many important cases, such as a vector, that representation is
only one or more pointers to data stored elsewhere, but that representation is
present in each object of a concrete class. That allows implementations to be
optimally efficient in time and space. In particular, it allows us to
- place objects of concrete types on the stack, in statically allocated memory,
and in other objects (§1.5);
- refer to objects directly (and not just through pointers or references);
- initialize objects immediately and completely (e.g., using constructors;
§2.3); and
- copy and move objects (§5.2).
The representation can be private (as it is for Vector; §2.3) and accessible only
through the member functions, but it is present. Therefore, if the representation
changes in any significant way, a user must recompile. This is the price to pay
for having concrete types behave exactly like built-in types. For types that don’t
change often, and where local variables provide much-needed clarity and
efficiency, this is acceptable and often ideal. To increase flexibility, a concrete
type can keep major parts of its representation on the free store (dynamic
memory, heap) and access them through the part stored in the class object itself.
That’s the way vector and string are implemented; they can be considered
resource handles with carefully crafted interfaces.
Last edited on
Very simple, there are 3 kinds of classes:
1. Abstract classes
2. Base/Derived classes (any derived can also be base)
3. Concrete classes

Diamond inheritance sample explains the first 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct Abstract
{
        virtual ~Abstract() = 0;
};

struct Base1 :
         virtual public Abstract
{};

struct Base2 :
         virtual public Abstract 
{};

struct Derived :
      public Base1,
      public Base2
{
       ~Derived() {};
};



And here is Concrete class

1
2
3
4
struct Concrete
{
        ~Concrete();
}


What's the big deal here?
Base and derived classes allow polymorphism, so the base destructor must be either public virtual or protected non virtual.

The purpose of Bases and derivates is that you can inherit from them,
you can call derived from pointer to base.
destruction process is well defined.
You can upcast/downcast and the behavior is well defined on use of the result.
The purpose is also that inheritance allows common behavior for derivates etc. etc.

On the other hand, the purpose of Concrete class is that is acts as "Final" and optionally single class, and thus does not need to provide virtual destructor.

Anyone who would attempt to derive from concrete class is potentially summoning demons to it's code, because concrete classes are not used for this.

As B. Stroustrup says, Concrete classes act as build in types. (you can't override build in type right?) makes no sense.

std::vector from B. Stroupstrup is perfect example of concrete class.

But that doesn't prevent you from deriving ie. from vector, but you must ensure safety, prevent inheritance of your class and ensure it's not used for polymorphism.
You should also document what' the purpose of your class, how it should be used and how it improves the std::vector "build in type" etc.

Quote from B.S. text:
The defining characteristic of a concrete type is that its representation is part
of its definition.


What means "representation" and what means "definition" and what means that "representation is part of definition"?

representation is what the class represents, and that is it's data members and methods which operate on that data, in the case of std::vector these are single type elements.

Since vector is concrete, it's data and logic is it's implementation.
What that means?

Compared to polymorphics classes the implementation can be in derived classes such as overrided by derivates, but it doesn't have to so 100%. user doesn't know and doesn't need to know this.

Concrete classes do not share it's implementation with derived classes by default, meaning it's implementation is "final" and here in that class, representation and definition are in one class, part of each other, not overriden not shared.
Last edited on
Thanks so much for your reply.
you can has-a concretes safely, though. A lot of problems don't need anything more than this, and it avoid unnecessary reams of code when doing simple things.

struct Concrete
{
~Concrete();
};

struct Concrete2
{
Concrete icanhaz; //its just a variable.
~Concrete2();
}

Last edited on
Yes, for the majority of cases a concrete class is what should be used, probably more than 90 percent. I've used them very much. What baffles me is the explanation Bjarne has used. Still it's uncomprehensible for me, although it may not be that important since I know how a concrete class works.
I interpret it as such

1
2
3
4
5
6
7
8
9
10
11
12
13
class Abstract
{
public:
    virtual void foo() = 0;
};

class Concrete : public Abstract
{
public:
    void foo() override;
private:
    int x;
}


The defining characteristic of a concrete type is that its representation is part
of its definition.


Because Abstract is a n abstract class, it cannot be created. It does not have a representation until you define the Concrete subclass. The definition of the Concrete class gives us its representation. The definition of the Abstract class only gives up an interface. We do not know how it is represented.

In particular, it allows us to
- place objects of concrete types on the stack, in statically allocated memory,
and in other objects (§1.5);
- refer to objects directly (and not just through pointers or references);
- initialize objects immediately and completely (e.g., using constructors;
§2.3); and
- copy and move objects (§5.2).


Obviously, an object of type Abstract cannot be created or statically allocated, etc. You need a concrete class to do all of this.

I could go through the rest of the quote, but this should get you thinking along the right lines.
The representation is what which is to be represented. So in the concrete class, that representation is the overridden function void foo() plus the private data member int x. Right?
Topic archived. No new replies allowed.