Is this typecasting in C++ or am I seeing things?
((YesNoQuestion*)first)->setAnswer(false);
((MultipleAnswerQuestion*)second)->setAlternative(2, "City2");
((MultipleAnswerQuestion*)second)->setCorrectAlternative(2);
And why is this done instead of just
first->setAnswer(false);
second->setAlternative(2, "City2");
second->setCorrectAlternative(2);
or
((YesNoQuestion)first)->setAnswer(false);
((MultipleAnswerQuestion)second)->setAlternative(2, "City2");
((MultipleAnswerQuestion)second)->setCorrectAlternative(2);
Doesn't the pointer provide the sufficient "identity" to make member functions of a child class viable for the parent class?
And why make the types pointers as well? Is it because the Question-objects are pointers that the new type has to be a pointer too?
Context:
These are answers from an old exam 5-6 years ago and everyone is on vacation now so I can't ask the professors who made it, but they did this in the main-file:
#include "MultipleAnswerQuestion.h"
#include "YesNoQuestion.h"
int main()
{
Question *first = NULL;
Question *second = NULL;
string alt[] = {"City1", "City2", "City3"};
first = new YesNoQuestion("Some statement here");
second = new MultipleAnswerQuestion("Some question here", alt, 3, 0);
((YesNoQuestion*)first)->setAnswer(false);
((MultipleAnswerQuestion*)second)->setAlternative(2, "City2");
((MultipleAnswerQuestion*)second)->setCorrectAlternative(2);
first->print(); //Prints Q
second->print(); //Prints Q
}
Abstract baseclass: Question(string question = "");
Children:
YesNoQuestion(string question = "", bool answer = true);
MultipleAnswerQuestion(string question, string alternatives[],
int nrOfAlternatives, int correctAnswer);
This depends on exactly how your classes are defined, but I'm guessing that your Question class does not have a setAnswer method that takes a bool. And since first is a Question pointer, and not a YesOrNoQuestion pointer, then you can't call YesOrNoQuestion methods on it.
The fact that first actually points to a YesOrNoQuestion object is irrelevant, since the compiler must be able to determine at compile time whether a call is valid purely based on the type of the variable.
In your example, you can simply make first be a YesOrNoQuestion pointer to avoid the casting. In more complex situations, it may not be that simple.
This is a type of type casting used for polymorphism. The first alternative you proposed would only work if the base class Question has virtual methods for setAnswer, setAlternative and setCorrectAlternative. If not, then you'd have to convert the pointer to the good class in order for the method to be found. The second alternative would not work because first and second are pointers, therefore their values are an addresses. Interpreting those addresses as objects of a class would not make sense in itself.
(Type*) is often know as C-style casting, this basically choose one from: const_cast, static_cast, reinterpret_cast. I don't like the last one, so I would use one of them.
The reason the cast is done, is most likely because Question doesn't contain the methods which are being called. Why would a generic Question have a setAnswer() which accepts a bool?
In this case, I would have written something like the following:
YesNoQuestion *firstTyped = new YesNoQuestion("Some statement here");
MultipleAnswerQuestion *secondTyped = new MultipleAnswerQuestion("Some question here", alt, 3, 0);
Question *firstUntyped = firstTyped;
Question *secondUntyped = secondTyped;
firstTyped->setAnswer(false);
secondTyped->setAlternative(2, "City2");
secondTyped->setCorrectAlternative(2);
firstUntyped->print(); //Prints Q
secondUntyped->print(); //Prints Q
Related
I did a bit of an experiment to try to understand references in C++:
#include <iostream>
#include <vector>
#include <set>
struct Description {
int a = 765;
};
class Resource {
public:
Resource(const Description &description) : mDescription(description) {}
const Description &mDescription;
};
void print_set(const std::set<Resource *> &resources) {
for (auto *resource: resources) {
std::cout << resource->mDescription.a << "\n";
}
}
int main() {
std::vector<Description> descriptions;
std::set<Resource *> resources;
descriptions.push_back({ 10 });
resources.insert(new Resource(descriptions.at(0)));
// Same as description (prints 10)
print_set(resources);
// Same as description (prints 20)
descriptions.at(0).a = 20;
print_set(resources);
// Why? (prints 20)
descriptions.clear();
print_set(resources);
// Object is written to the same address (prints 50)
descriptions.push_back({ 50 });
print_set(resources);
// Create new array
descriptions.reserve(100);
// Invalid address
print_set(resources);
for (auto *res : resources) {
delete res;
}
return 0;
}
https://godbolt.org/z/TYqaY6Tz8
I don't understand what is going on here. I have found this excerpt from C++ FAQ:
Important note: Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object, just with another name. It is neither a pointer to the object, nor a copy of the object. It is the object. There is no C++ syntax that lets you operate on the reference itself separate from the object to which it refers.
This creates some questions for me. So, if reference is the object itself and I create a new object in the same memory address, does this mean that the reference "becomes" the new object? In the example above, vectors are linear arrays; so, as long as the array points to the same memory range, the object will be valid. However, this becomes a lot trickier when other data sets are being used (e.g sets, maps, linked lists) because each "node" typically points to different parts of memory.
Should I treat references as undefined if the original object is destroyed? If yes, is there a way to identify that the reference is destroyed other than a custom mechanism that tracks the references?
Note: Tested this with GCC, LLVM, and MSVC
The note is misleading, treating references as syntax sugar for pointers is fine as a mental model. In all the ways a pointer might dangle, a reference will also dangle. Accessing dangling pointers/references is undefined behaviour (UB).
int* p = new int{42};
int& i = *p;
delete p;
void f(int);
f(*p); // UB
f(i); // UB, with the exact same reason
This also extends to the standard containers and their rules about pointer/reference invalidation. The reason any surprising behaviour happens in your example is simply UB.
The way I explain this to myself is:
Pointer is like a finger on your hands. It can point to memory blocks, think of them as a keyboard. So pointer literally points to a keypad that holds something or does something.
Reference is a nickname for something. Your name may be for example Michael Johnson, but people may call you Mike, MJ, Mikeson etc. Anytime you hear your nickname, person who called REFERED to the same thing - you. If you do something to yourself, reference will show the change too. If you point at something else, it won't affect what you previously pointed on (unless you're doing something weird), but rather point on something new. That being said, as in the accepted answer above, if you do something weird with your fingers and your nicknames, you'll see weird things happening.
References are likely the most important feature that C++ has that is critical in coding for beginners. Many schools today start with MATLAB which is insanely slow when you wish to do things seriously. One of the reasons is the lack of controlling references in MATLAB (yes it has them, make a class and derive from the handle - google it out) as you would in C++.
Look these two functions:
double fun1(std::valarray<double> &array)
{
return array.max();
}
double fun2(std::valarray<double> array)
{
return array.max();
}
These simple two functions are very different. When you have some STL array and use fun1, function will expect nickname for that array, and will process it directly without making a copy. fun2 on the other hand will take the input array, create its copy, and process the copy.
Naturally, it is much more efficient to use references when making functions to process inputs in C++. That being said, you must be certain not to change your input in any way, because that will affect original input array in another piece of code where you generated it - you are processing the same thing, just called differently.
This makes references useful for a bit controversial coding, called side-effects.
In C++ you can't make a function with multiple outputs directly without making a custom data type. One workaround is a side effect in example like this:
#include <stdio.h>
#include <valarray>
#include <iostream>
double fun3(std::valarray<double> &array, double &min)
{
min = array.min();
return array.max();
}
int main()
{
std::valarray<double> a={1, 2, 3, 4, 5};
double sideEffectMin;
double max = fun3(a,sideEffectMin);
std::cout << "max of array is " << max << " min of array is " <<
sideEffectMin<<std::endl;
return 0;
}
So fun3 is expecting a reference to a double data type. In other words, it wants the second input to be a nickname for another double variable. This function then goes to alter the reference, and this will also alter the input. Both name and nickname get altered by the function, because it's the same "thing".
In main function, variable sideEffectMin is initialized to 0, but it will get a value when fun3 function is called. Therefore, you got 2 outputs from fun3.
The example shows you the trick with side effect, but also to be ware not to alter your inputs, specially when they are references to something else, unless you know what you are doing.
edit on Feb 25: changed my question, and adding some describes to my question.
======================some complains===========================
To those people who down-vote my question:
This is my first question on stack-overflow.
about the question: this question was emerged from my thought. in my case, I thought the return 0 actually did something for my
program, and it absolutely did. The only thing could misunderstand
people is probably I gave a question that I think it works like that
way but it didn't.
about my attitude. Maybe you guys here are expert in C++ and you might think my question is stupid. However, as a non-English-native speaker, this question is took me 4 hours to think and do the test, 2 hours for searching on google but also took me at least half hour to post. As a self-taught newbie I already tried my best to make the question as best as I could.
Thus, please at least leave a comment to let me know what I could improved about the way I submit my question, when you do the downvote. Do not just make a simple click. Your click is just like a new question to make me consider: "am i did something wrong?" "how could I solve it?" It is going to force me to reconsider what I’ve done; but just like the normal questions, It would be help if someone could give some tips.
As a newbie, I won't stop to raise questions; so I think point out my problems will help me to improve my ability to raise high quality questions, and you will benefit also because you might see some good questions in future.
At last, thanks again for this place; I got a lot answers from here; And also thanks for those people who helped me to solved my problem.
=======================question line======================
This function I intend to get an array argument by using "using alias form", and trying to return the array itself back to the calling function. I tried to use pointer and reference both for this function.
here is what I learned from C++ primer:
using arrT = int[10];
arrT* func(int i);
This code is suppose to define a function that would return a pointer that point to a array with ten ints; I understand this, but I didn't get a example from book.
and here are my tries:
using pointer, trying to return the pointer directly, but error.
arrT* return_p(arrT arr){
for(int i = 0; i < 10; ++i){
*(arr+i) *= 2;
}
return arr;//error, can't convert int* to int (*)[10]
}
i know because here arr is converted and lost the array's dimension. However, I just found a way that works for me:
arrT* return_p(arrT arr){
for(int i = 0; i < 10; ++i){
*(arr+i) *= 2;
}
return 0; // return 0 is return pointer arr that point the first element of array arr.
}
I just wondering how did the return 0 work here? And I do have another result here if I use reference instead of using pointer:
arrT& return_r(arrT &arr){
for(auto &i : arr){
i *= 2;
}
return arr; // works, returned the reference to array named arr
}
but return 0 is not working for the reference version.
arrT& return_r(arrT &arr){
for(auto &i : arr){
i *= 2;
}
return 0; // error, using an int rvalue to initialize a non_const that has type int(&)[10];
}
I hope I told my question clearly. thanks for your help!
The literal 0 is a "null pointer constant", and it can be used to initialize a value of any pointer type (object pointer, function pointer, member pointer or void pointer). The result of this initialization is the null pointer value of that type.
There is no concept corresponding to that of "null pointer" for references: references are always bound to objects or functions. For pointers the "null" value is in some way a distinguished value that says "not the address of anything". And by contrast, a reference is not allowed to not be bound to anything. That's why your last example is ill-formed.
Incidentally, you can return the address of an array if you pass the array as a reference:
arrT * f(arrT & a) { return &a; }
What's confusing about array types is that arrays cannot be passed to or returned from functions by value, but the corresponding syntax is allowed -- it is allowed, but means something different: f(arrT x) actually means the same as f(int * x) in your case.
In more technical terms, arrays can only be passed and returnd as and glvalues, but not as prvalues.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am trying to create a constructor that sets an array field to null.
Im getting a "no viable overloaded '=' " error
Horse::Horse()
{
string *ptr;
ptr = NULL;
Name[SIZE] = ptr;
}
My question is what exactly is going on behind the scenes here. I thought I could create a string pointer, set it to null, then set the array to the pointer and it would make the first element of the array equal to null?
Thanks
Setting Name[SIZE] to point to the address of std::string * is meaningless.
If Name is a std::string array, then the array will be defaulted empty.
If your task was to set the Name field empty in the constructor, I'm going to assume this is a const char* instead of a std::string. This can be done using initializer list:
Horse::Horse()
: Name{0} // Name{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} does the same thing.
{} // empty body
The above will initialize all the 20 positions to 0, or NULL if you like. Just as if you declared it in the global scope.
If you are not familiar with the initializer list in constructors, you can always do this, but at an extra cost:
Horse::Horse() // Initialize members runs first
{
for (int i = 0; i != SIZE; ++i) // Assign values to Name array
Name[i] = 0;
}
Side note: Instead of using macros to define your values, a better choice is to use const unsigned SIZE = 20; for reasons described here
I'll just go ahead and write the whole thing for you.
If you think about what a name is, it's just a string, a string of characters. So Name should be a std::string. Then the constructor would look like this:
Horse::Horse() {}
Done. Name will be initialized to an empty string, i.e. "".
If the assignment requires you to use C-strings (char arrays) instead of std::string, then Name should be of type char*, if it needs to be set to NULL. Now the constructor would look like this:
Horse::Horse() : Name(NULL) {}
The Name field will be initialized to NULL, i.e. it will be a null pointer, hence it doesn't contain even an empty string.
If I define an variable:
int (**a)[30];
It is pointer. This pointer points to a pointer which points to an array of 30 ints.
How to declare it or initialize it?
int (**a)[10] = new [10][20][30];
int (**a)[10] = && new int[10];
All doesn't work.
The direct answer to your question of how to initialize a (whether or not that's what you actually need) is
int (**a)[10] = new (int (*)[10]);
I don't think this is actually what you want though; you probably want to initialize the pointer to point to an actual array, and either way std::vector is the better way to do it.
If you want an answer to the question as it stands, then you can do this kind of thing:
int a[30];
int (*b)[30] = &a;
int (**c)[30] = &b;
But it's unlikely to be what you want, as other people have commented. You probably need to clarify your underlying goal - people can only speculate otherwise.
Just to follow on from MooingDuck's remark, I can in fact see a way to do it without the typedef, but not directly:
template <typename T>
T *create(T *const &)
{
return new T;
}
int (**a)[30] = create(a);
It's not pretty though.
What do you expect to get by writing &(&var)? This is an equivalent of address of address of a block of memory. Doing things like this just to satisfy the number of * in your code makes no sense.
Think about it - how can you get an address of an address? Even if, by some sheer luck or weird language tricks you manage to do it, there no way it will work.
I'm building a comparator for an assignment, and I'm pulling my hair out because this seems to simple, but I can't figure it out.
This function is giving me trouble:
int compare(Word *a, Word *b)
{
string *aTerm = a->getString();
string *bTerm = b->getString();
return aTerm->compare(bTerm);
}
Word::getString returns a string*
Error:
In member function `virtual int CompWordByAlpha::compare(Word*, Word*)':
no matching function for call to...
...followed by a bunch of function definitions.
Any help?
You're comparing a string to a string pointer, and that's not valid. You want
return aTerm->compare(*bTerm);
You aren't getting the different uses of the * operator. The use of the * in "string* bTerm = b->getString()" means "bTerm is a pointer to a string". The use of the * inside of compare(*bTerm) means "take the value of the location pointed to by bTerm" instead of just using compare(bTerm) which simply attempts to compare the value of bTerm itself, which is a hex address.
This is also happening on the left side of that call:
aTerm->compare(*bTerm); //this statement
(*aTerm).compare(*bTerm); //is the same as this statement
The -> operator just reduces the amount of typing required.
P.S.: This kind of stuff you could have easily figured out from Google or your programming textbook. Although others may disagree, I don't feel that questions about completely basic syntax have any place on Stack Overflow.