ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
See "No high-level built-in types"
See "Manual memory management"
Most of what I do in C++ can't be done in Java because Java pretends like objects are these nebulous things that have no underlying structure. Because of that, one can't use pointers, not to mention nested pointers, which are critical to a lot of C++ (pointers aren't actually outdated; you don't see JVM written in Java.) This prevents a significant portion of the useful C/C++ code out there from working in Java without significant restructuring, namely by creation of wrapper classes to simulate references. Additionally, Java's "memory management" means "I'll clean it up when I feel like it," much like a custodial contractor who says emptying your own trash is a contract violation. Java and C++ cannot be fairly compared, despite their syntactic and semantic similarities. Java isn't "the new C++" just as C++ isn't "the original Java."
Kevin Barry
Most of what I do in C++ can't be done in Java because Java pretends like objects are these nebulous things that have no underlying structure. Because of that, one can't use pointers, not to mention nested pointers, which are critical to a lot of C++ (pointers aren't actually outdated; you don't see JVM written in Java.) This prevents a significant portion of the useful C/C++ code out there from working in Java without significant restructuring, namely by creation of wrapper classes to simulate references. Additionally, Java's "memory management" means "I'll clean it up when I feel like it," much like a custodial contractor who says emptying your own trash is a contract violation. Java and C++ cannot be fairly compared, despite their syntactic and semantic similarities. Java isn't "the new C++" just as C++ isn't "the original Java."
Kevin Barry
You don't even see JVM written in C++ - it's written in "C".
src/main.cpp:7: error: no matching function for call to ‘TopLevelWindow::TopLevelWindow(Application*, const char [10], Dimension)’
src/TopLevelWindow.h:16: note: candidates are: TopLevelWindow::TopLevelWindow(Application*, Dimension, std::string)
That says you called a function using parameter types: Application*, const char [10], Dimension
but you defined the function using parameter types Application*, Dimension, std::string
The C++ compiler generally can do an implicit conversion from const char[10] to std::string. But it can't switch the operand sequence. You defined the function with the Dimension third and std::string second, but called it with those reversed.
After you fix that bug, maybe the code will compile. If not, you should post the relevant code. The makefile plus the error messages is usually not enough for us to guess what error you made.
$ make
g++ -c -lX11 -I /usr/include/cairo -lcairo -Werror src/main.cpp
src/Widget.h: In function ‘int main()’:
src/Widget.h:27: error: ‘void Widget::show()’ is inaccessible
src/main.cpp:8: error: within this context
src/main.cpp:8: error: ‘Widget’ is not an accessible base of ‘TopLevelWindow’
make: *** [main.o] Error 1
Once again, you have quoted multiple error messages (compile time and run time) from the first few lines of main() in your code. You posted lots of code and never the lines containing the errors.
Quote:
Originally Posted by MTK358
Still, wouldn't it be nice if you could write C as if structs had inheritance, and run it through a special program that turns it into C?
Doesn't sound like a good idea. You think you would do a better job of extending C into OO than the designers of C++ did. Even with a better job (which is unlikely and difficult) merely a little better doesn't balance the fact that C++ is already in widespread use.
Quote:
Originally Posted by MTK358
But doesn't this concept break the OO rule of private, protected, and public? Why do you have to decide suddenly?
Why does it break any OO concept.
You accessed the Widget part of TopLevelWindow from outside TopLevelWindow. If you want to do that, Widget must be public in TopLevelWindow.
If you don't want Widget to be public in TopLevelWindow, then TopLevelWindow must provide some interface to do whatever it was that you wanted to do on line 8 of main.cpp (which you didn't show us).
Possibly a using declaration gives you a way to achieve what you want (expose only part of Widget to users of TopLevelWindow). I'm not 100% sure myself what you can/cannot do with using. I don't often want to expose only part of a base class. I use using a lot to cover a trickier flaw in the C++ language involving inheritance from templated base classes.
Quote:
Originally Posted by MTK358
found that the way they say C++ debugging info is not human readable is true:
Yes. It is unreadable. But not so unreadable that you can't easily tell something is going wrong in the constructor of TopLevelWindow. Of course you showed us only the declaration, not the definition (nor the call to it from main), consistent with your apparent policy of never showing any of the lines where the errors occur.
I misunderstood the way BaseClass : public DerivedClass works. And I still don't understand why you would ever want to block access to the part of your class inherited from base.
I misunderstood the way BaseClass : public DerivedClass works.
But you understand now?
Quote:
I still don't understand why you would ever want to block access to the part of your class inherited from base.
If you always want your base classes public, always make your base classes public.
I usually make base classes public (whether they ought to be or not) because I don't really believe in the supposed benefits of maximum encapsulation. But I still have found reasons (in complex projects) to make base classes private, so I'm glad I have the option to do so.
I think we needed to see the whole definition of that constructor, especially the way it invokes the base class constructor. If you let it use the default constructor for the base class, I don't think that is a valid way to inherit your Widget class (and wouldn't be in any OO langauge).
Quote:
That debug message still doesn't even give me a clue to what's wrong. In C debug messages are usually quite obvious, however.
I use too many different debuggers, so I didn't initially see what was what in the gdb output you quoted. Even in C, when your program trashes its own context that badly before the seg fault, the debugger will often display nonsense.
Your code constructed a temporary std::string containing "test" and then called the TopLevelWindow constructor. Inside that constructor, the code trashed the memory occupied by that temporary std::string before the string went out of scope.
You may need to single step into the constructor and into or over each of the things the constructor does, in order to discover the moment at which some probably unrelated write steps on the memory used by that temporary std::string.
I programmed in assembly language for many years before I ever tried C++, so I use an assembly language view for debugging any C++ bug as tricky as the one you seem to have. If you know assembly language, these bugs are usually far easier to diagnose in an assembler view.
EDIT: I found the problem, the part that I left out is highlited in red. Now it actually shows a window on the screen.
And I don't know Assembler. The only working assembly program I have written was for an 8-bit AVR microcontroller to blink a few LEDs.
But I hope to learn eventually. It still puzzles me the way I keep hearing that the memory addreses are preset in the executable, what if there is not enough memory? Or that address is used? How does it call parts of other programs?
EDIT: I found the problem, the part that I left out is highlited in red. Now it actually shows a window on the screen.
I think I see how you managed to get away with letting the compiler generate a default construction of the base class rather than explicitly calling the base class constructor yourself. But that is an error prone style, and I strongly suggest you get in the habit of explicitly calling base class constructors whenever the base class requires interesting initialization.
In these situations, I usually do a typedef for super and then use super, rather than the actual base class name everywhere else within the current class. That style has significant benefits as your projects get more complex, even more so when inheriting from templated classes.
In C++, a class may have more than one base class. So the language could not have been designed (like Java) to define super for you. Even with multiple base classes, I usually find that only one of my base classes is conceptually "super". Then that typedef also serves to tell maintainers of the code which base class I considered "super" in designing this class.
So
Code:
class TopLevelWindow : public Widget {
typedef Widget super;
private:
//Nothing!
public:
TopLevelWindow(Application* app, Dimension size, std::string newTitle);
};
I don't understand your code well enough to know what you want for Widget* parent_, Dimension location in that call to super(), but I suspect you ought to be making those explicit (rather than using the default constructor).
I also prefer to use struct rather than class, because I don't like excessive encapsulation, I like to put the public interface first, I like public to be the default and initial state and private or protected to need to be explicit.
The problem is that the TopLevelWindow obviously does not have a parent Widget.
One solution may be to add a parameter-less constructor for Widget.
So I can write "typedef <base class> super;" and that will call the base class constructor? Will calling "super.method()" call the base class's implementation of the method?
And I still think I would like to use class instead of struct because my classes often have a few private fields and I think it's convenient to have them there at the top. I prefer to use structs the way they are used in plain C.
The problem is that the TopLevelWindow obviously does not have a parent Widget.
Is Widget designed to expect self for the top level parent pointer or NULL?
Whichever it is, I think it is more maintainable code to make that explicit in construction of TopLevelWindow, rather than buried in a compiler generated call to the base class default constructor.
If the implementation of parentless is encapsulated inside Widget (as it probably should be) and should not be known by TopLevelWindow, then it should require an explicit parentless constructor of Widget. The special case of a parentless Widget should not be constructed by the default constructor of Widget.
In a lot of my code, I have an empty class named Nothing. In overloads of a function or constructor where not providing a certain parameter is a special enough case to deserve being highlighted at the point of call, I define an overload that takes a Nothing const& as a parameter and explicitly passes Nothing() to satisfy it. (There is no run time overhead to passing Nothing() to a Nothing const&. It just determines which overload is chosen at compile time).
Quote:
One solution may be to add a parameter-less constructor for Widget.
You already declared (and I assume defined) a parameter-less constructor for Widget. I was questioning whether it was a good idea to use that constructor.
Quote:
So I can write "typedef <base class> super;" and that will call the base class constructor?
The typedef just defines the identifier super. By itself, it does not change any generated code. The compiler defaults to calling the parameter-less Widget constructor.
You could call a Widget() constructor yourself in a TopLevelWindow constructor if you wanted to. I just think it is better style to define super and then call the super() constructor instead of the Widget() constructor.
Quote:
Will calling "super.method()" call the base class's implementation of the method?
If you don't define super, then you call base class implementation explicitly with Widget::method(). If you do define super, you can call base class implementation with super::method().
I think the later is usually more maintainable code.
When the base class is templated, you find a lot of need for typedef typename super::name_of_type name_of_type;
and using super::name_of_member;
to bring names from the base class into scope for definition time syntax checking of the current class (templated base class names may be in scope when current class methods are instantiated, but aren't when current class methods are defined, so you may need to force them into the definition time scope.)
Is Widget designed to expect self for the top level parent pointer or NULL?
Whichever it is, I think it is more maintainable code to make that explicit in construction of TopLevelWindow, rather than buried in a compiler generated call to the base class default constructor.
If the implementation of parentless is encapsulated inside Widget (as it probably should be) and should not be known by TopLevelWindow, then it should require an explicit parentless constructor of Widget. The special case of a parentless Widget should not be constructed by the default constructor of Widget.
In a lot of my code, I have an empty class named Nothing. In overloads of a function or constructor where not providing a certain parameter is a special enough case to deserve being highlighted at the point of call, I define an overload that takes a Nothing const& as a parameter and explicitly passes Nothing() to satisfy it. (There is no run time overhead to passing Nothing() to a Nothing const&. It just determines which overload is chosen at compile time).
The Widget constructor is based around the concept that it is the child of another Widget. A TopLevelWondow's parent is NULL, and TopLevelWindow is a very special case of Widget, mainly because of the fact that it's "parent" is an X Window (usually the root window) instead of another Widget, so it's initialization is quite different and I think it would not be a good idea for Widget itself to handle that case, because it will just make all the other "normal" widgets more complicated. For that reason, I would just make an empty constructor for Widget.
But it still seems kind of confusing for normal widgets.
Maybe it would be best for TopLevelWindow not to be a subclass of Widget but be independent?
Note that the intended class hierarchy was actually Widget->Container->TopLevelWindow, where Container is a widget that holds a single widget with variable padding on all sides (Just about everything but text boxes and labels will be a subclass of Container, borrowing the idea from GTK+ that text labels in widgets are actually child Label widgets). I just did Widget->TopLevelWindow to get results quick.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.