22

C++ is a multi-paradigm language and STL and Boost are built towards the functional paradigm of the language. STL is composed of containers (to hold data), iterators (to access data) and algorithms (functions to manipulate data). Algorithm functions are applied on containers by using iterators. As a side-effect, these methods are not part of the container classes, but are completely separate. (This avoids redundancy for the library writers, but is painful for library users.)

Are there C++ alternatives to STL/Boost which offer such containers in a more traditional object-oriented flavour? I am looking for strings, vectors, linked lists, map, trees, hash tables and such. Containers should be easy to inherit and extend. In comparison, extending classes from STL/Boost is a very bad idea and this is by design of their designers.

PS: Please do not use the reply space below to pontificate the advantages of STL/Boost. I am well aware of them! :-)

Community
  • 1
  • 1
Ashwin Nanjappa
  • 76,204
  • 83
  • 211
  • 292
  • Yes. It's called [ACE](http://www.cse.wustl.edu/~schmidt/ACE.html). ;-) – C. K. Young Apr 27 '11 at 05:00
  • 8
    I think may you misuse terms [imperative](http://en.wikipedia.org/wiki/Imperative_programming) and [functional](http://en.wikipedia.org/wiki/Functional_programming) programming. – beduin Apr 27 '11 at 05:02
  • Beduin: C++ supports both of those flavours of programming. If you are coming from Lisp, of course C++'s functional programming constructs will look kludgy! :-) – Ashwin Nanjappa Apr 27 '11 at 05:06
  • 2
    Chris Jester-Young: Please reply instead of commenting, so folks can vote on your answer and expand it with descriptions. – Ashwin Nanjappa Apr 27 '11 at 05:07
  • @Ashwin: My original suggestion was facetious. (ACE is commonly considered to be a C++ kitchen sink.) But yes, ACE actually does have the containers you seek, so, I might write up a real answer. :-P Still not sure if it's too heavyweight for you, though. – C. K. Young Apr 27 '11 at 05:26
  • 3
    What pains have you had extending STL containers, and why do you claim "it is a veritable minefield to properly use them", and that Java/C# is easier/better? If you elaborate - perhaps someone can address your actual concerns...? (For example, if it's forwarding constructors and non virtual destructors, I don't see that as a significant impediment given templated constructors can forward adequately and the "extensions" you mention don't even add data members). – Tony Delroy Apr 27 '11 at 05:46
  • Tony: Extending STL containers is a *very* bad idea. See: http://stackoverflow.com/questions/679520 – Ashwin Nanjappa Apr 27 '11 at 05:50
  • 8
    @Ashwin: not at all, inheriting from them is a bad idea, extending them (using composition) is perfectly natural. – Matthieu M. Apr 27 '11 at 06:52
  • 4
    Note that extending a container via inheritance usually doesn't satisfy the liskov substitution principle. Hence you are asking for a library that does bad OO (or class orientation, really). – ltjax Apr 27 '11 at 07:13

8 Answers8

31

Many (most!) older libraries for C++ used containers that bore a much closer resemblance to those used in such things as Java and C#.

A few example of such libraries include COOL, ET++, the NIH Class Library, and Rogue Wave Tools.h++.

Two points:

  1. At most, these are a source if inspiration. I'm pretty sure it's been at least 10 years (and often more like 20) since any of them has been updated. There's virtually no chance that any of them will even compile with any reasonably current compiler.
  2. I want to go on record as pointing out that I'm providing links to these only in answer to a very specific question. I most assuredly do not recommend that you use any of the above code, nor do I recommend that you even use them as inspiration.

To be sure I'm clear here, at least IMO:

  • The allegations in your question are utterly false.
  • What you're trying to do is completely insane!
  • You're wasting your time.
  • Writing code this way is a really, really bad idea. Just say no!
  • If you insist on doing this, you will become a pariah.
    1. Even non-programmers who don't quite understand why, will begin to hate you intensely.
    2. Your dog will use your shoes and bed as his toilet.

You're on your own. You have been warned!

Closed captioning for the humor impaired: of course some of that is meant to be humorous -- it is a really, really lousy idea though

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
26

This avoids redundancy for the library writers, but is painful for library users.

I don't agree with this premise at all. And even if I did, it's a huge over-generalization that doesn't apply to every library user. But this is a subjective statement anyway, so I'll ignore it.


Are there C++ alternatives to STL/Boost which offer such containers in a more traditional object-oriented flavour?

...

Containers should have methods that allow one to manipulate on them directly. (For example, calling vector.sort() instead of sort(vector.begin(),vector.end()).

Sure. Just make your own containers that have the standard containers as data members and delegate calls to them and to algorithms as needed via member functions. It's rather trivial to implement:

template<typename T>
class MyVector
{
public:
    void sort()
    {
        std::sort(vec.begin(), vec.end());
    }

    // ...
private:
    std::vector<T> vec;
};

There's nothing in C++ that prevents you from doing something like this, ironically thanks to the multi-paradigm nature of C++ that you seem to not agree with.

You can probably use private inheritance and using declarations if you much rather not write out wrapper functions.


STL/Boost make it a pain to derive from their containers and extend them.

That's because you're not supposed to derive from them. The proper way is to use composition, like the code snippet I presented above.

In silico
  • 51,091
  • 10
  • 150
  • 143
  • 2
    In silico: With composition you end up re-writing wrappers for all the needed methods again. I have done this, it is painful. – Ashwin Nanjappa Apr 27 '11 at 05:49
  • 11
    The whole goal of the STL was the easy extensibility of container. Just add another non-member non-friend function and you're done. If you'd want to extend a container in your proposed implementation, THAT would be a pain. – Xeo Apr 27 '11 at 05:53
7

You're heading the wrong way. If you want to program in Java then program in Java. If you program in C++ then program as C++ programmers do. Always swim with the current, never against it.

wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
  • 3
    I'm sorry if this is precisely the answer you're not interested in. But C++ is not an "object oriented language". It's plain wrong to try to be "object oriented purist" with C++. – wilhelmtell Apr 27 '11 at 05:42
  • Wilhelmtell: The problem is that there is no ONE flow in C++. You are wrong, C++ is OO. But, it is also imperative, procedural, functional and God knows what else! :-) STL/Boost take one of the possible directions with C++. Every great hacker has only used one such direction or subset of C++, see: http://gigamonkeys.wordpress.com/2009/10/16/coders-c-plus-plus/ – Ashwin Nanjappa Apr 27 '11 at 05:45
  • 1
    @Ashwin: I guess I'm not a "great hacker" since I have used multiple paradigms in (non-trivial) C++ programs because some problems are easier solved using different strategies. After all, every "great hacker" used only one. Never mind my [35 Nice Answers, 24 Enlightened, 2 Good Answer badges and the 800+ upvotes for the `c++` tag](http://stackoverflow.com/users/308661/in-silico). – In silico Apr 27 '11 at 05:50
  • 4
    @Ashwin: "But, when you want to build something large with a team, you will need to enforce usage of only a subset of C++." - Again, I don't agree with this premise. Why would one need to enforce usage of only a subset of C++? Especially if that subset happens to be the cleanest way to solve a problem? – In silico Apr 27 '11 at 05:58
  • 1
    In silico: Not denying your prowess, but I try to learn from others. The book Coders At Work and the above blog post both have the thoughts of hackers on C++ and I tend to agree with them from my own C++ experience. Please read the post for more. – Ashwin Nanjappa Apr 27 '11 at 05:59
  • 2
    @Ashwin: And I never said you did. But please consider how other people who may not agree with your provided blog post do things, in addition to those you agree with. We're not morons; if the "STL-way" was so bad we wouldn't be using it! – In silico Apr 27 '11 at 06:08
  • 1
    In silico: I am sorry if you felt offended. I myself am using STL in many of my programs. I felt the need for a non-STL approach and this question was the result. As others have pointed out, there are libraries with a non-STL approach like Qt which serve such an audience. – Ashwin Nanjappa Apr 27 '11 at 06:12
  • @Ashwin: There's no need to be sorry because I wasn't offended in anyway (although the nitpick in me can't resist [telling you about the "politician's apology"](http://blogs.msdn.com/b/oldnewthing/archive/2007/02/26/1763692.aspx)). :-) – In silico Apr 27 '11 at 06:19
  • In silico: Politician's apology, I was not aware of that. Thanks for pointing it out :-) – Ashwin Nanjappa Apr 27 '11 at 06:23
  • 1
    The correct Java way would also be "prefer composition to inheritance" :-). – helpermethod Apr 27 '11 at 08:14
  • 4
    @Ashwin: Why do you keep insisting that Qt's approach is different than STL. This is not true! – Emile Cormier Apr 28 '11 at 13:06
7

STL and Boost are as object-oriented as you can get.

  1. For all theoretical purposes, member function and a free function overloaded on the first argument are the same thing. They behave very similarly in practice, including for inheritance, so in C++ you should really consider free functions taking (possibly const) reference as first arguments to be methods of their first argument.

    Advantage of free functions is they can be defined for existing class allowing you to add an interface to existing class. Which is why STL and especially boost uses them so much. Main advantage of member functions is they can be virtual (but virtual methods should be private anyway!)

  2. You don't want to extend collections by derivation. Generally, you don't want to extend anything by derivation unless it is an abstract base class specifically designed for it. See this question about advantages of composition over inheritance.

Community
  • 1
  • 1
Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
  • one caveat of free functions. ADL requires functions to be defined in the namespace of one of their arguments. It is undefined behavior to add a function to the `std` namespace. /cry – Matthieu M. Apr 27 '11 at 06:54
  • 1
    But you are allowed to specialize std name space members _for User Defined Types_ – sehe Oct 15 '12 at 16:28
5

Take a look at Qt's approach, I have always been a fan of it.

updated the link.

Kiruahxh
  • 1,276
  • 13
  • 30
OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • OneOfOne: Thanks. Qt is actually the only library I know which has followed this approach! I was hoping someone would point out other alternatives :-) – Ashwin Nanjappa Apr 27 '11 at 05:53
  • 16
    What?! The Qt containers are almost the same as the STL containers. No virtual functions, no included sort statements, etc. How are they any different? – edA-qa mort-ora-y Apr 27 '11 at 07:35
  • broken link, please fix – tuket Apr 23 '17 at 18:13
  • I like Qt containers too, they are convenient. They have useful methods such as QList::contains, QList::operator <<, the QStringList::join(), QString::split... I would like it to be the standard. Also, having no namespace is handy for writing shorter code. std namespace has grown too big, its members can collide with you code therefore only few projects contain `using namespace std` – Kiruahxh Dec 18 '20 at 11:27
0

Why don't use graph instead of STL containers and attach what you need on nodes or edges. They can mimic any STL containers (Am I wrong?). You can easily iterate over nodes or edges (DFS, BFS) and along the way you can do what you like to do with data attached on nodes and edges. Easy mix of algorithm and iterator, isn't it?

Dilawar
  • 5,438
  • 9
  • 45
  • 58
0

What Dilawar stated is actually the solution for all your container needs.

Use Boost::graph or a similar implementation. You can use it [that is what I do] as a object management system.

As for the criticism of STL, it's just a matter of taste and not technical objections. These exist, but not at this level.

0

Coming a little late to this party AND I know the OP is specifically asking to not "pontificate" as they already know about the STL, however ...

There is an old Dr. Dobbs interview with Alex Stepanov, a pioneer in generic programming and a primary contributor to the STL. It is very instructive a several ways, especially to address the question of why more standard OO techniques are not used in the STL. One paragraph stands out:

Even now C++ inheritance is not of much use for generic programming. Let's discuss why. Many people have attempted to use inheritance to implement data structures and container classes. As we know now, there were few if any successful attempts. C++ inheritance, and the programming style associated with it are dramatically limited. It is impossible to implement a design which includes as trivial a thing as equality using it. If you start with a base class X at the root of your hierarchy and define a virtual equality operator on this class which takes an argument of the type X, then derive class Y from class X. What is the interface of the equality? It has equality which compares Y with X. Using animals as an example (OO people love animals), define mammal and derive giraffe from mammal. Then define a member function mate, where animal mates with animal and returns an animal. Then you derive giraffe from animal and, of course, it has a function mate where giraffe mates with animal and returns an animal. It's definitely not what you want. While mating may not be very important for C++ programmers, equality is. I do not know a single algorithm where equality of some kind is not used.

For those preferring a Java answer to this same conundrum, Josh Bloch takes pains to make the same points in Effective Java, Item 8: Obey the general contact when overriding.

It's a good chapter, with a nice example about trying to preserve the equals contract while at the same time extending a simple Point class with and added color: a ColorPoint class. He goes on to demonstrate that there is a fundamental limitation of OOP: there is no way to extend an instantiable class AND add a value component while preserving the equals contract.

Granted, the Bloch statement is more succinctly stated, but they both (correctly) draw the same conclusions. The main difference is that Java is (was) a "pure OO" language - everything must reside in a class, even those things such as algorithms, which are not naturally objects.

And I think Bloch may be sensitive to this problem because he has seen it fail spectacularly in the Java library: Stack inheriting from Vector is one example of a notable design problem in Java.

Slightly later in the interview, Stepanov goes on to say:

I had participated in several discussions early on at Bell Labs about designing templates and argued rather violently with Bjarne that he should make C++ templates as close to Ada generics as possible. I think that I argued so violently that he decided against that. I realized the importance of having template functions in C++ and not just template classes, as some people believed. I thought, however, that template functions should work like Ada generics, that is, that they should be explicitly instantiated. Bjarne did not listen to me and he designed a template function mechanism where templates are instantiated implicitly using an overloading mechanism. This particular technique became crucial for my work because I discovered that it allowed me to do many things that were not possible in Ada. I view this particular design by Bjarne as a marvelous piece of work and I'm very happy that he didn't follow my advice.

DaveParillo
  • 2,233
  • 22
  • 20