|
Let me expand a bit on my previous answer[^].
As I said, you can convert a pointer (or reference) to pointer (or reference) to the base class. This called "upcasting" because you are moving "up" in the inheritance tree. The conversion is "non-destructive", in other words you can later on "downcast" (move from base to derived) as long as you know what type of object was in the first place. An example:
struct Unit {
Unit (int tag) : dog_tag(tag){};
virtual std::string kind () = 0;
int dog_tag;
};
struct Soldier : public Unit {
Soldier (int tag) : Unit(tag) {};
virtual std::string kind() {return "soldier";};
float running_speed;
}
struct Sailor : public Unit {
Sailor (int tag) : Unit(tag) {};
virtual std::string kind() {return "sailor";}
int life_jackets;
};
std::vector<Unit*> actors {new Soldier(555), new Sailor(666);};
int main () {
Unit* u0 = actors[0];
std::cout << "Actor 0 is a " << u0.kind() " with tag " << u0.dog_tag << std::endl;
If you would look with a debugger at u0 you would see a memory layout something like this:
-------- ------------------------------
u0| 0x1234 |------->| pointer to vtable of Soldier |
-------- |------------------------------|
| dog_tag |
| -----------------------------|
| running_speed |
------------------------------
You can see now why the code works: no matter what kind of object you deal with, the first part of the memory layout is the same. Compiler simply ignores whatever is after the dog_tag field.
A few more lines of code (please ignore that I didn't initialize other fields):
Soldier *s = (Soldier *)u0;
std::cout << "Running speed " << s->running_speed << std::endl; s has exactly the same value as u0 but compiler considers it a pointer to a Soldier object so it uses the value from the running_speed field. I could have written:
Sailor *ss = (Sailor*)u0;
std::cout << "Sailor has " << ss->life_jackets << " life jackets"; And compiler wouldn't have cared at all. It would have accessed the memory at life_jackets location as an integer and this is that.
Now, what happens if I use dynamic_cast instead of C-style casts?
Sailor *ss = dynamic_cast<Sailor*>(u0) The generated code would have used the value stored in the vtable member to check if the 0x1234 truly is a Sailor object. As the vtable value doesn't match the address of vtable for Sailor objects, the dynamic cast operation would have returned a NULL pointer.
Things to remember from this story:
- upcast is always safe. Downcast not so much.
- dynamic_cast is safer than C-style cast provided you check the result.
- dynamic_cast works only for classes that have at least one virtual function. If your object doesn't have a virtual table compiler cannot figure out what type of object it really is.
Mircea
|
|
|
|
|
The intelisense was bogus - I missed including "ui" header.
Thanks for all the help, it is much appreciated.
modified 10-Aug-24 22:07pm.
|
|
|
|
|
|
As a rule, I don't post a reply unless I can really answer the original question. I'm going to make an exception this time hoping that you will find my comments useful.
1. After you finished your question, look at it through the eyes of a stranger and ask yourself if he/she has enough information to answer it or if it is too much information. In this case "I have a working "connect" within an object and need to extend it to "connect" between objects." Doesn't tell me much I would have to learn Qt and, as you properly noticed, Qt is not a favourite around here. If it's a C++ question show the relevant C++ fragment followed by a pseudo-code of what you try to accomplish.
2. Format your code properly. Use the toolbar to wrap code fragments in <pre lang="C++"></pre> tags and indent your code to make it easier to read. I know it is a bit of work involved but doing it, shows that you care about your question otherwise, if you don't care about the question, other people might not care to answer it.
Please rephrase your question as a C++ one and I'll do my best to try to answer it. Surely other people, with even more expertise will do the same.
Mircea
|
|
|
|
|
Please stop deleting your questions, as it makes the replies impossible to understand. You have been here long enough, in all your different names, to know how this site works.
|
|
|
|
|
DELETED
-- modified 10-Aug-24 12:52pm.
|
|
|
|
|
Your code snippet is very difficult to read with all of the comments and lack of indentation.
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles
|
|
|
|
|
Let`s say I have a cocktail of objects of different type but having the same base class. Would it be possible to store the cocktail into a C++ array rather then a stl container?
class soldier : public unit
{
public:
void RunSM1();
};
unit* LUnits;
int lunitcount = 2;
int main()
{
LUnits = new unit[lunitcount];
LUnits[0].Init();
soldier * S = new soldier();
&LUnits[1] = S;
LUnits[1] = *S;
return 0;
}
modified 8-Aug-24 7:01am.
|
|
|
|
|
Yes, it is possible. Moreover, it is very common to do that.
When you access the objects you can convert a pointer to base to the derived type using either dynamic_cast or a specialized type function:
Soldier *s = dynamic_cast<Soldier*>(LUnits[0]);
if (!s)
printf("Element 0 is not a soldier\n");
s = dynamic_cast<Soldier*>(LUnits[1]);
if (s)
printf ("Element 1 is indeed a soldier\n");
Mircea
|
|
|
|
|
|
Yes, it is possible with correct casting, if you are just storing pointers. But you still need to know what type each entry is next time you refer to them. Also the line &LUnits[1] = S; is incorrect, you do not need the leading & character. So you can store them with something like:
soldier * S = new soldier();
LUnits[0] = dynamic_cast<unit*>(S);
sailor* AB = new sailor();
LUnits[1] = dynamic_cast<unit*>(AB);
sailor* tar = dynamic_cast<sailor*>(LUnits[1]);
soldier* squaddie = dynamic_cast<soldier*>(LUnits[1]);
[edit]
@Mircea-Neacsu provides a clearer explanation above.
[/edit]
modified 8-Aug-24 8:51am.
|
|
|
|
|
Let me respectfully comment:
soldier * S = new soldier();
LUnit[0] = S;
sailor* AB = new sailor();
LUnit[1] = AB;
sailor* tar = dynamic_cast<sailor*>(LUnits[1]);
soldier* squaddie = dynamic_cast<soldier*>(LUnits[1]);
For details see: dynamic_cast conversion - cppreference.com[^]
Mircea
|
|
|
|
|
Thank you, I was working from memory instead of reviewing some code I wrote years ago.
|
|
|
|
|
I need to know how to execute the conversion in both directions, I find your post still useful.
modified 8-Aug-24 11:57am.
|
|
|
|
|
Thank you for your comment.
|
|
|
|
|
I have a window containing some data. I need to add functionality to add notes anywhere in window. Please guide.
|
|
|
|
|
You need to provide considerably more details of the code you are using and exactly what you are trying to do. As it stands it is impossible to suggest anything useful.
|
|
|
|
|
Anywhere means nothing.
What do you want to do, exactly ?
What is or what kind of data in your window ?
How is it represented ?
What kind of notes you want to add ?
What relation has the note and the data ?
Do you have an example of something similar you want to do ?
Without more details...
I'd handle a click or double click event, open a modal popup window with a text box, and on the OK button, save the note whereever you want to save the note.
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
Why don't the enumeration objects get recognized unless the enumeration is defined in the same header file where the enumeration object is created? If the enumeration is in a different header file I get an
"Error C3646 'PC': unknown override specifier " error. I`m including the header file where enumeration is defined in the header where the enum object is created.
|
|
|
|
|
|
Thank you Victor. I will change the object name to lower caps and see if the error goes away
|
|
|
|
|
Since it is demonstrated that the community has no (technical) interest, or perhaps lacks knowledge in helping in resolving the issue , hence this post, as is , has no change to be resolved here and is also unwelcomed here ,
<b>it is therefore voluntarily removed.</b>
|
|
|
|
|
jana_hus wrote: This post is here because I should be able to ask,
Wrong!!! YOU don't get to dictate what you can or cannot post here. That's for the community and moderators to decide. This forum is specifically for standardC/C++ (with the addition of MS MFC), because that's what the moderators wanted. There's no mention of QT, or WxWidgets or any other C++ frameworks.
As I said in one of my earlier posts, get a copy Stroustrup: The C++ Programming Language (4th Edition) If your question can't be covered by the material therein, then ITS NOT A C++ QUESTION!!!. I only have the 2nd edition of that book, and QT isn't covered at all. I'm sure that it's not covered in the 4th edition either. So, as always, this question belongs in a forum that's dedicated to QT and its use, not here!
"A little song, a little dance, a little seltzer down your pants"
Chuckles the clown
|
|
|
|
|
The community IS the moderator.
|
|
|
|
|
jana_hus wrote: This post is here because I should be able to ask,
if it bothers you - DO NOT REPLY. Thanks.
Oh look, it's another Salvatore Terress.
|
|
|
|