Class hierarchy/dependency diagram generator for C++ in Linux - c++

Is there some tool to generate class hierarchy/dependency diagrams by inspecting C++ code in Linux?
I have this big collection of C++ files given to me and such a tool would be invaluable to help me
understand the source code. I am getting a little tangled up in understanding it.

Try doxygen. It may also be shipped with your distribution.
You may need GraphViz to generate the graphs. There is a simple example and output.
And this is a more complicated example from the legend file generated by doxygen:
Code (NOTE: if you only want to generate the graphs, the comments are not required.):
/*! Invisible class because of truncation */
class Invisible { };
/*! Truncated class, inheritance relation is hidden */
class Truncated : public Invisible { };
/* Class not documented with doxygen comments */
class Undocumented { };
/*! Class that is inherited using public inheritance */
class PublicBase : public Truncated { };
/*! A template class */
template<class T> class Templ { };
/*! Class that is inherited using protected inheritance */
class ProtectedBase { };
/*! Class that is inherited using private inheritance */
class PrivateBase { };
/*! Class that is used by the Inherited class */
class Used { };
/*! Super class that inherits a number of other classes */
class Inherited : public PublicBase,
protected ProtectedBase,
private PrivateBase,
public Undocumented,
public Templ<int>
{
private:
Used *m_usedClass;
};
Result:
You do not need to comment your code to generate these graphs. The first example has no comments at all. The second example has one class without doxygen style comment. Just set the appropriate parameter (at least EXTRACT_ALL = YES should be set. I cannot recall whether this is all that is needed).

There's a promising new tool called cpp-depenencies.
It can generate component dependency diagrams (like below) as well as class hierarchy diagrams (by passing an option to treat each source file as a component).
There's also cpp_dependency_graph, which is able to generate component/include dependency graphs in dot, d3.js or JSON formats.
Below is an example d3.js visualisation.
Disclaimer - I am the author of cpp_dependency_graph.

If you use Eclipse as IDE, you can use type hierarchy to see class hierarchy.

If you use kdevelop, you could install kdevcontrolflowgraphview plugin.

Source Trail is an easy-to-use tool in my experience with an intuitive GUI that helps you explore the relationship between a language element and others that are related to it. It worked very well for me on MacOS.
As of September 2021, it is no longer developed, but the repository remains available.

Related

interfacing gobject with C++

I’m trying to create a custom audio sink plugin for gstreamer using the Gst::AudioSink as a base class. For me this involves multiple learning curves as I’m new to gstreamer, gstreamermm and gobject. Also I have no background or real interest in gtkmm as I’m not working on GUI code at present.
I am trying to create a class along the lines of:
class MyAudioSink: public Gst::AudioSink
{
public:
explicit MyAudioSink(MyAudioSink *gobj);
virtual ~MyAudioSink();
static void class_init(Gst::ElementClass<MyAudioSink> *klass);
virtual int write_vfunc(gpointer data, guint length) override;
virtual void reset_vfunc();
};
I seem to missing some magic in the class_init() function that should link the base class functions to the virtual functions in MyAudioSink.
In C we would do something like:
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstAudioSinkClass *audio_sink_class = GST_AUDIO_SINK_CLASS (klass);
audio_sink_class->write = GST_DEBUG_FUNCPTR (myaudiosink_write);
I don’t really grok the C++ binding to gobject.
What is the equivalent for linking to the C++ virtual function hierarchy?
I got the impression from Marcin’s video https://gstconf.ubicast.tv/videos/gstreamermm-c-way-of-doing-gstreamer-based-applications/ that the virtual functions should be invoked automatically.
I can create a half usable (doesn’t handle things like EOS) plugin by adding:
add_pad(sinkpad = Gst::Pad::create(get_pad_template("sink"), "sink"));
sinkpad->set_chain_function(sigc::mem_fun(*this, &MyAudioSink::chain));
But I don't think a sink should have a chain function.
I've also asked this question on the gtkmm mailing list. If I get an answer there I will post it here.
For MyAudioSink I get a class hierarchy of:
GObject +----GInitiallyUnowned
+----GstObject
+----GstElement
+----myaudiosink
Rather than:
GObject +----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstBaseAudioSink
+----GstAudioSink
+----myaudiosink
I suspect this is the essence of my problem.
For the audiofilter example Marcin mentions here I get a class hierachy of:
GObject +----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstBaseTransform
+----GstAudioFilter
+----myaudiofilter
You can find examples of writing your own plugin in the repository: https://git.gnome.org/browse/gstreamermm/tree/tests/plugins/derivedfrombasetransform.h
In general, your header looks ok, and full implementation should look (more or less) like that:
class MyAudioSink: public Gst::AudioSink
{
public:
explicit MyAudioSink(KantarAudioSink *gobj)
: Glib::ObjectBase(typeid (MyAudioSink)),
Gst::AudioSink(gobj) {}
static void class_init(Gst::ElementClass<MyAudioSink> *klass)
{
// Y
klass->set_metadata("longname", "classification", "description", "author");
klass->add_pad_template(Gst::PadTemplate::create("sink", Gst::PAD_SINK, Gst::PAD_ALWAYS, Gst::Caps::create_any()));
}
virtual int write_vfunc(gpointer data, guint length) override {}
virtual void reset_vfunc() {}
};
Very recently we had a bug report when someone posted very nice, tiny example of audiofilter plugin, you can use it as an example for your project as well: https://bug794249.bugzilla-attachments.gnome.org/attachment.cgi?id=369564
If this doesn't work, feel free to file a bug here: https://bugzilla.gnome.org/enter_bug.cgi?product=gstreamermm
It turns out that much of my troubles were caused by cutting and pasting
this into MyAudioSink class:
static GType get_base_type()
{
return Element::get_base_type();
}
This had the effect of telling gobject that my class is based on gstElement which was wrong.
I thought it was some innocent cast like incantation.
This shows the perils of cut and paste but more than that the perils of coding blindly.
I was also guilty of oversimplifying the sample code I pasted here such that no-one my question doesn't show the problem.
That fixes my problem but does not answer my question.
I will try to summarise that below.
"What is the equivalent for linking to the C++ virtual function hierarchy?"
To create a wrapper to a gobject class the normal process is to use glibmmproc.
The wrapper is defined by files with extension .hg and .ccg from which the C++ interface and a gobject wrapper are generated.
For example to wrap a gobject classs foo you might create Foo.hg and Foo.ccg.
glibmmproc would then generate Foo.h and Foo.cc.
Foo.cc includes most of your definition of the Foo class but with
an additional gobject wrapper Foo_class.
Foo_class is a gobject class which wraps gobject virtual functions (vfunc_callbacks) and forwards them to Foo
allowing derived classes of Foo to use C++ inheritance and C++ virtual functions.
The boilerplate is hidden and a C++ developer need for the most part only worry about the C++ interface provided by Foo.h
One way to understand the internals is to build gstreamermm from source and study the code generated by glibmmproc.
For my case this would be: gstreamermm/audiosink.cc & gstreamermm/audiosink.h generated from
src/audiosink.ccg and src/audiosink.hg
So how does the derived C++ class register itself?
Gst::ElementFactory::register_element() - registers the class with gstreamer
Gst::register_mm_type - records the inheritance relationship
See your local /usr/include/gstreamermm-1.0/gstreamermm/register.h for the implementation
Glib::ObjectBase(typeid (MyAudioSink)) is not required in my case as I am not using multiple inheritance. However it is critical in other applications which do. See for example Implementing a custom gtkmm treemodel

How to get Doxygen to ignore inheritance relationship?

I'm trying to get Doxygen to ignore an inheritance relationship when drawing collaboration diagrams.
Let's say my class definition looks like this:
class Derived : public Base
{
int x;
int y;
int z;
}
Now, when I run Doxygen, I don't want to see Base class in the generated collaboration diagram.
At first glance, it seems that the cleanest way to do this would be to use the EXCLUDE_SYMBOLS directive in my Doxyfile. Specifically:
EXCLUDE_SYMBOLS = Base
However, I've found that this does not work: The Base class still shows up in my collaboration diagram for Derived. I've tried this on both Doxygen 1.8.6 and 1.8.11 and with different permutations of Base wildcards (Base*, *as*, etc), same behavior. The Base class always shows up in my collaboration diagram.
To be fair, I have found 2 workarounds, but they both involve putting conditional statements into my code. For completeness, I'll include both here:
First Workaround Method:
class Derived :
#ifndef DOXYGEN_SHOULD_SKIP_THIS
public Base
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
{
...
}
Then ensure that the following two directives are set inside the Doxyfile:
PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS
ENABLE_PREPROCESSING = YES
Second Workaround Method:
class Derived :
/// #cond DOXYGEN_IGNORE
public Base
/// #endcond
{
...
}
To be clear, these workarounds do indeed make Doxygen ignore the inheritance relationship, but I'd prefer not to unnecessarily pollute my code base, especially if there's a better / cleaner way to accomplish my goal.
My question is -- Why doesn't EXCLUDE_SYMBOLS make Doxygen ignore my Base class when it draws the collaboration diagram?
If i am not mistaken, EXCLUDE_SYMBOLS prevents Doxygen from generating documentation for the excluded symbols, but it does not hide them. This means Doxygen won't generate documentation for your Base class, but it will still mention it as the base class of Derived, just like if Derived inherited from a class provided by an external library, the name of the class provided by the library would appear in the collaboration diagram.

Doxygen C++ - Not documenting virtual functions in a template class

I have a template class that has a bunch of pure virtual and implemented virtual functions. I then have children inherit from this class. I want to document the functions in the virtual parent class and have children inherit this documentation in Doxygen.
For example (I can't post the real source).
template <typename A>
class Parent {
/** Documentation
*/
virtual void pure() = 0;
/** More Docs
*/
virtual void notpure() {
...
}
};
In a different file with all proper includes (at least for the compiler)
class Child: public Parent<int> {
void pure() {
...
}
};
I then want Doxygen to generate documentation for both classes with the same documentation for each function unless I re-document the overridden function.
I run Ubuntu 14.04 and use the repository Doxygen 1.8.6 in case it matters.
Thank you
So, I will answer my own question. Sort of.
If anyone has this same problem, be sure to check for comment bugs. Doxygen handled my templates fine, but I did have a problem because I have the habit of putting /* code /**/ in my programs so I can quickly uncomment large blocks of code quickly while debugging. Doxygen does not like this!.
I had the error message
File ended in the middle of a comment block! Perhaps a missing \endcode?
It took me a while to wade through the warnings generated because I had several undocumented files. This was taken care of by using
EXTRACT_ALL = YES
In my config file. HERE is someone who has a similar problem as I was.
According to the INHERIT_DOCS tag, it should already do that if you have it set to 'yes'.
AFAIK doxygen has had some problems with parsing templates classes and that might be the reason why your documentation isn't being duplicated (i.e. doxygen thinks Child inherits from a different Parent class).
You might try to force this behavior by using the \copydoc command. If that still doesn't work you might have to either ask for a patch or fix it yourself.
I've had a similar problem generating docs of an abstract class. The solution was to make the methods public (by default in a C++ class all methods are private and you need to set EXTRACT_PRIVATE to YES in your Doxygen config file for docs be generated).
I hope this helps someone!

Class dependency graph with doxygen

I want to generate a class dependency graph for a large project in C++. I'm trying to do it with doxygen. Here is the sample code:
class Used {
public:
void bar();
};
class Base { };
class Derived : public Base {
public:
void foo(Used*); // Dependency on class Used
};
Here is the collaboration diagram generated by doxygen:
Nice, but Derived depends on Used through the method foo, and I want to see this on the diagram, like this:
Unfortunately, doxygen generates such dependency only if Used is aggregated with Derived (used as a class member). Is there a way to show other kinds of dependencies between classes?
Or maybe someone can suggest a different tool to generate such a dependency graph?
I tried to use CppDepend, it does exactly what I want, but unfortunately it currently has some issues with dependencies in a really big project (though the dev team is open for communication and has already fixed a couple of bugs I reported).

Override a Qt class with an embedded private class

In many cases, I would like to override a Qt class to extend or modify its behavior. But almost all Qt classes uses an internal private class such as QNetworkDiskCachePrivate inside QNetworkDiskCache. I know there are advantages of this approach. But there is a HUGE problem of the private class: it makes overriding the class a lot more difficult. With other C++ class library with source code, I usually override a class method, copy the code from the implementation in the parent class and make small modifications here and there to achieve the behavior I want. However, in Qt, the private class is not exported and not visible to the derived class. Since Qt classes maintains the critical internal data in the private class through the "d" member, the invisibility of the private internal class makes the possibility of behavior extension very limited. You can only play with the few exposed public method.
I tried extracting the entire source files of the class and renaming the class name and file names. But the Qt class library is so much intertwined that extracting a single class out of it is messy as well in most cases.
Do I miss something here? Or Qt classes are just really bad in terms of extendability?
Qt classes are better than most in terms of extendability; they often have hooks to change their behavior without resorting to copying and pasting an entire method. Having said that, if the generally accepted methods of extending don't work, yes the Qt classes are harder to hack. That's probably a good thing because copying-pasting-and-modifying the base class implementation means that your derived class won't get any improvements or bugfixes that are made in the base class implementation.
If you want to do it, you're going to need to convince your build system to let you include the private headers and then refer to the private classes from your new implementation. Pay attention to the disclaimer in the Qt docs; when you do this you are opening yourself up to breakage with every new version of Qt that is released (Qt only guarantees the public API, and you're messing with its internals). Qt's public API is wonderfully readable and documented; the internal code can be pretty cryptic, so you really, really want to be sure that you can't accomplish what you want with the public API. If you're still resolved to use the private class stuff, this might help.
Your approach is wrong and bad! To extend a Qt, and more in general C++, code you don't have to copy the source code and modify it where you need. You should (have to) use extending OOP(Object Oriented Programming) paradigm. In C++ you should write something like:
#include <iostream>
using namespace std;
class A
{
public:
A(){x=1;}
void writeName(){cout << "my name is A";}
void writeNumber(){cout << "my number is " << x << endl;}
private:
int x;
};
class B : public A
{
public:
B(){}
void writeName(){cout << "my name is B and i'm better then A" << endl;}
};
int main()
{
B *b= new B();
b->writeName();
b->writeNumber();
return 0;
}
//output:
my name is B and i'm better then A
my number is 1
In this way B does all that base class A does and you add your methods(extend base class) to fit your needs. If you take a look at qt example code this is usually the approach used to do something not included into default qt widget behaviour. In example ItemDelegate customizations: you write your own class MyItemDelegate that extend QItemDelegate: link
Or Qt classes are just really bad in terms of extendability?
Qt is "only" a framework build up C++ language. This means that everything you can do in C++ you can do with Qt.