I am learning c++ from 'Teach yourself c++ in 21 days' by Liberty and Jones. Compiler I am using is gcc 6.3.0. I am on pointer topic. First I am writing one code similar to the one book gives which works fine. Here it is:
#include <iostream>
using namespace std;
class Cat
{
public:
Cat();
int Getage() {return *itsage;}
private:
int *itsage;
};
Cat::Cat()
{
itsage=new int;
*itsage=2;
}
int main()
{
Cat *Mani=new Cat;
cout << "Mani is a cat whose age is: " << Mani->Getage();
cout << endl;
return 0;
}
Output: Mani is a cat whose age is: 2
Now instead of using constructor, I thought of using accessor function to set age. I wrote the following code which gave me output as above but I have doubt why this code work. Here is the code I wrote.
#include <iostream>
using namespace std;
class Cat
{
public:
void Setage(int age) {*itsage=age;}
int Getage() {return *itsage;}
private:
int *itsage;
};
int main()
{
Cat *Mani=new Cat;
Mani->Setage(2);
cout << "Mani is a cat whose age is: " << Mani->Getage();
cout << endl;
return 0;
}
Doubt: What I studied so far tells me that whenever pointer declared, it should get initialized, i.e. we should assign some memory address to it. In the first code, we are initializing our pointer member variable in the constructor by this command itsage=new int; which looks fine. But in the second code, I nowhere assigned any memory address to pointer itsage. But still code worked fine. I am little confused here.
I have one more doubt(I am asking here itself as it is related to the above code. If it's bad, I will ask it in different question.) I thought of making pointer itsage in the above code public. But I don't know how can I access it. I tried the following but didn't work.
#include <iostream>
using namespace std;
class Cat
{
public:
int *itsage;
};
int main()
{
Cat *Mani=new Cat;
Mani->*itsage=2;
cout << "Frisky's age is " << Mani->*itsage;
return 0;
}
So how to access public pointer member variable of object created on heap?
Thanks.
About your first question. I was confused at first, this is a neat answer, which shows that the compiler did it for you.
About your second question, it's nothing but an improper way of accessing the pointer. You should realize that when trying to access the content of a pointer, you must get its address then go to its content. So you need to:
Get its address: Mani -> itsage
Access its content: *(Mani -> itsage)
In this function:
void Setage(int age) { *itsage=age; }
you are dereferencing itsage, but it's not pointing to valid memory. This invokes undefined behavior. You need to do:
void Setage(int age) {
itsage = new int;
*itsage=age;
}
For the second question, the correct syntax to access a member variable of pointer type is:
*(Mani->itsage) = 2;
Note that this is undefined behavior too, for the same reason as above. The fix is also the same; you need to do:
Mani->itsage = new int;
*(Mani->itsage) = 2;
But in the second code, I nowhere assigned any memory address to pointer itsage. But still code worked fine. I am little confused here.
That's a fair doubt. In fact, your 2nd code should never work, as no memory had ever been allocated to itsage. If it still somehow "worked" for you then it is still a typical undefined behaviour.
You should still allocate the memory before usage as usual, and free it in the constructor. As your class doesn't even have a destructor, perhaps you should choose unique_ptr instead:
class Cat
{
public:
void Setage(int age) { itsage = make_unique<int>(age); }
int Getage() { return *itsage; }
private:
unique_ptr<int> itsage;
};
Related
With regards to this piece of code:
#include <iostream>
class CClass1
{
public:
void print() {
std::cout << "This should print first" << std::endl;
}
};
class CClass2
{
public:
void print() {
std::cout << "This should print second" << std::endl;
}
};
So someone asked an interesting question about having a "free pointer" (so to speak) which can point to multiple instances of different objects without having to create a new type of that object. The person had the idea that this pointer can be of type void * and since it is void, it can be made to point to any instance of an object and access the object's public properties.
The following solution was submitted:
int main() {
void *pClass(NULL);
((CClass1 *)(pClass))->print();
((CClass2 *)(pClass))->print();
std::cin.ignore();
return 0;
}
My question is why does the above work, but this doesn't:
int main() {
(CClass1 *FG)->print();
(CClass2 *FG)->print();
std::cin.ignore();
return 0;
}
Your first example exhibits undefined behavior, by calling a non-static member function via a pointer that doesn't point to a valid object. It only appears to work by accident, because the function in question just happens not to use this in any way.
Your second example is, quite simply, syntactically incorrect. I'm not even sure what you are trying to do there; the code makes no sense.
I have an object with a method that needs to mutate an outside instantiated object. I've been trying to reference the object in the parameter and that is clearly not working. This is what I have:
#include <iostream>
#include <cstdlib>
#include "Character.h"
using namespace std;
class TesterClass {
public:
void printStuff();
TesterClass(Character& userChar);
private:
Character& character;
};
TesterClass::TesterClass(Character& userChar)
{
character = userChar;
}
int main() {
Character userCharacter;
TesterClass tester(userCharacter);
return 0;
}
My question is how to can I use the instantiated tester class to edit the Character object via parameter passing. I'm very new at C++ and I've read every perceivable definition of reference and point passing, and it just doesn't seem to want to click.
Your constructor should be:
TesterClass::TesterClass(Character& userChar):character(userChar){}
Also see this question.
To address the comment, here's example code where the value is modified:
#include <iostream>
#include <cstdlib>
typedef char Character;
using namespace std;
class TesterClass {
public:
void printStuff();
TesterClass(Character& userChar);
private:
Character& character;
};
TesterClass::TesterClass(Character& userChar):character(userChar)
{
}
void TesterClass::printStuff() {
cout << character << endl;
cout << ++character << endl;
}
int main() {
Character userCharacter = 'a';
TesterClass tester(userCharacter);
tester.printStuff();
cout << userCharacter << endl;
++userCharacter;
cout << userCharacter << endl;
tester.printStuff();
return 0;
}
The output is
a
b
b
c
c
d
I agree with the previous answer/comments - You really should use an initialization list in your constructor. The thing is that your data-members are initialized through the initialization list (this happens BEFORE the body of the constructor is called). In your case, you have a Character& as a member. Since this is a reference, it HAS to be assigned something. I'm not sure which compiler you're using, but AFAIK that code shouldn't even compile.
What you're probably looking for is passing the reference in your main-method, like:
int main()
{
Character userCharacter;
// Notice the use of the &-operator
TesterClass tester(&userCharacter);
return 0;
}
At this point, you're no longer talking about a Character-instance, but of the memory address of the instance. So, since you're passing the mem-address, it's actually a pointer you need in your class, not a reference. (For instance, userCharacter.SomeMethod() is synonymous to (&userCharacter)->SomeMethod() where & references and -> dereferences).
Instead, you could write your TesterClass as:
class TesterClass
{
public:
void printStuff();
TesterClass(Character* userChar);
private:
Character* character;
};
TesterClass::TesterClass(Character* userChar)
: character(userChar) // <- Notice the init-list
{}
That way, in your TesterClass instance, you'll have a pointer that points to the same memory address where the userChar-instance resides.
As a sidenote: It can be good to notice though that userCharacter is a local variable, which means that it'll be destroyed when it runs out of scope. In this case it's not really a problem since tester is local as well. But if you're not used to working with pointers - Just a word of caution. Make sure you never pass the pointer (since you're storing the address in a class member) to a TesterClass-object that lives beyond the scope of the variable whose reference you're passing. That'll leave you with a dangling pointer.
I hope that helps you :)
As you can see I am new to C++, but I can't understand why y = new Person() in function foo is wrong. Thanks for your help.
I get the this error:
error: no match for ‘operator=’ in ‘y = (((Person*)operator new(32u)),
(, ))’
UPDATE:
I will accept the answer with the most upvotes by tonight or the one that is more convincing.
The argument between me and my friend is wether the function foo can change the object and propagate the change outside the function like when doing y = Person(), then also brother will change or will it remain intact?
.
CODE:
#include <iostream>
using namespace std;
class Person {
public:
int age;
char name[25];
Person() {
age = 0;
}
};
void foo(Person &y)
{
y = new Person();
}
int main()
{
Person *brother = new Person();
brother->age = 20;
cout << "age = " << brother->age << endl;
foo(*brother);
cout << "age = " << brother->age << endl;
return 0;
}
You probably come from a language were objects can only be created with new. In C++, this is not the case. And unless you really need it, you should not use new. Just create it as a normal variable:
#include <iostream>
#include <string>
class Person
{
public:
unsigned age;
std::string name;
Person(unsigned age, std::string name)
: age(age)
, name(std::move(name)) // move is C++11
{}
};
int main()
{
Person brother(8, "Tim John");
std::cout << "age = " << brother.age << '\n';
// Edit regarding the question in the comments:
brother = Person(16, "John Tim");
std::cout << "age = " << brother.age << '\n';
}
Your problem with the code above is that new returns a Pointer, and you are trying to assign a pointer to a Person, which obviously can't work.
void foo(Person &y)
{
y = new Person();
}
y is a reference, not a pointer. To reassign to y, you'd use
y = Person();
but if you really want to allocate a new person, you'd use
void foo(Person* &y) // reference to pointer to Person
With a reference, you basically say that you modify the value at the calling site.
Note that your current code leak. If you have a bare pointer that you want to manage yourself, you have to delete it first:
void foo (Person*& y)
{
delete y;
y = new Person;
}
But as you see, the code is already becoming messy without knowing your target. It might be more appropriate to delete at the calling site, or to not allocate y at all before calling foo(...).
Also note that using foo (Person* y) instead would not solve the issue of newing at the calling site:
void foo (Person *y)
{
y = new Person();
}
This of course compiles, but modifies only foo's own y variable. The caller will have an unchanged pointer.
Note that you'd better use value types or smart pointers, as it is non-trivial to write exception safe code that manually manages memory.
In function foo the line should be
y = Person();
y is not a pointer.
EDIT: actually, this is the wrong answer (even though you're currently accepted it from Jon). You are not supposed to mix heap and stack, and cause memory leaks like that. The right way to do it is to change members of the object directly. Assignment operator (operator=) will change the members of the object. Because the question is not about mixing heap and stack, but about changing object here's the code that better explains the problem. Note that there's no new here to complicate the issue.
void foo(Person &y)
{
y = Person();
}
int main()
{
Person brother;
brother.age = 20;
...
foo(brother);
...
return 0;
}
After y = Person() the brother object will be changed because y is brother and assignment operator changes the members of the object.
Never confuse yourself with the & and * operators when dealing with pointer operations.
'&' is used in different context.
&, when used in a function's formal parameters is a reference parameter , this operator passes a variable by reference(by its address).However the variable y still acts like a normal variable.
So this block of code..
void foo(Person &y)
{
y = new Person();
}
would not work as new Person() is parsing a pointer to a variable.
For example,
int * intp = new int;
int variable = intp;
this is the type of thing that's happening here.A reference parameter acts like a variable but actually has direct access to the variable due to the fact that it's a call by referance operation.
The correct way to write this function will look like this
void foo(Person ** y)
{
*y = new Person();
}
That is if you're trying to initialize a class pointer via a function.
As cooky said this is a misconception people make in c++ whom program in languages that require the new keywork in order to create an object/variable.
SOURCES
http://fredosaurus.com/notes-cpp/functions/refparams.html
you are tryng to call the "new" operator on a reference. while the "new" is used only with pointers.
pass to void foo( ) function
Person*
instead of
Person&
A little explanation :
The right way to pass a parameter depends on what you have to do!!
If you want to do side effects to the object passed to the function the right way is to declare :
void foo(Person& person)
the object person can be modified..
if you don t waant to do side effects to the object you have to declare the object 'const':
void foo(const Person& person)
the const means you cannot modify the object inside your method even if you are passing a reference..
then you can pass a pointer:
void foo(Person* person)
here you can modify the object that "person" is pointing at, but you have a copy of the original pointer.
last way to pass parameters is :
void foo(Person*& person)
here you have an alias of the original pointer. alias means "the same pointer with a different name"
I need a little bit of help with using pointers in C++. Sorry to seem beginner but I really can't quite understand them. I have read the tutorial on pointers on the cplusplus.com website, so please don't suggest that.
I basically have a variable which holds the name of another variable, and I wish to access that variable through the holder one. I believe I need to use pointers, correct me if I'm wrong though.
E.g.
int a;
string b;
a = 10;
b = "a";
I need to access the variable "a" through the contents of variable "b".
Just to put this into better perspective, this is how I am using it:
int a;
a = 20;
void getVar(string name) {
cout << name;
}
getVar("a");
But as you can see, on the fifth line, that will just cout the value of name, in this case "a", but I want it to cout the value of the variable which name contains, so I want it to output "20".
Any help here would be much appreciated.
If you need to associate a name with a value, consider associative arrays otherwise known as dictionaries and maps. The Standard Template Library has std::map that you can use to associate text with a value:
#include <map>
#include <string>
std::map<std::string, int> my_map;
my_map["A"] = 20;
cout << my_map["A"] << endl;
What you are thinking of is called (Reflection) which C++ does not support. You can however use pointers to access what is in a variable it points to:
int a = 5; //int variable that stores 5
int *b = &a; //int pointer that stores address of a
(*b) = 10; //stores 10 into address that b points to (a)
cout << a; //prints 10
What you are trying to achieve is not possible in a compiled language (not considering reflection). You might accomplish something similar using a map data structure.
theMap["a"] = 20;
and a corresponding
void getVar(string key){
cout << theMap[key];
}
that can be called with
getVar("a");
Note that in this extremely simple sample theMap has to be in scope for the function, like in a class or a namespace.
If you use pointers you are just using a level of indirection not at all suited for your example. See Chads answer for instance.
Theres no real way for you to access variables by name like that unless you create some kind of container class that has a name member that you look up by. I'm not sure what this has to do with pointers though.
What you're asking for is called "reflection" or "introspection" - the ability to use design-time names for your program's objects (classes, variables, functions, etc) in run time. C++ does not support that out of the box - the design-time names are stripped upon compilation.
There are some libraries that provide that capability in C++; but there are also languages where reflection is is part of the language. Python or JavaScript, for example.
Maybe this could suit you:
int a = 5;
class b {
public:
b(int &x) { ref_ = x; }
int operator()(void) { return ref_; }
private:
int &ref_;
}
b my_b(a);
my_b() /* -> 5 */;
Your code does not use pointers. you're trying to convert a string into an identifier and print it's result, I don't know whether that's possible or not. If you intended using pointer your code should've looked like this:
int a = 20;
int* b = &a;
cout << *b;
quick fix for outputting integers only:
int a;
a = 20;
void getVar(int name) {
cout << name;
}
getVar(a);
If you need the function to work for any type of variable, maybe think about some template function.
Edit: Here is the code for the template program:
#include <iostream>
#include <string>
using namespace std;
template <class T>
void getVar(T name){
cout<<name<<endl;
}
int main()
{
string x="hee";
int y=10;
getVar(x);//outputs hee
getVar(y);//outputs 10
return 0;
}
I am learning C++ and i currently have some questions that i don't know the answers. I create this header file Object1.h and can compile this file but when i run the Test.cpp, Visual Studio throw an error because of access violation by *sibling. The strange thing is I can run it using Dev C+ and it return only value 2.Therefore I want to ask why assigning *sibling will create an error and why i can't change Person B's address using setAddress(). I will really appreciate if any one can give me some answer or hints. Thanks in advance.
//This is Object1.h
#include <iostream>
using namespace std;
class Person{
public:
Person(int ID);
void setAddress(string addr);
string getAddress();
void addSibling(Person *p);
Person getSibling();
int ID;
private:
string address;
Person *sibling;
};
Person::Person(int ID){
this->ID = ID;
}
void Person::setAddress(string addr){
this->address = addr;
}
string Person::getAddress(){
return address;
}
void Person::addSibling(Person *p){
*sibling = *p;
}
Person Person::getSibling(){
return *sibling;
}
//This is Test.cpp
#include <iostream>
#include <string>
#include "Object1.h"
using namespace std;
int main(){
Person A(1);
Person B(2);
A.addSibling(&B);
// Change the address of person B through person A's getSibling()
A.getSibling().setAddress("123 Street");
cout << B.getAddress() <<endl;
cout << B.ID;
system("Pause");
return 0;
}
Using operator * assumes that you deal with some data resided by address stored in this variable. Let's review your code:
*sibling = *p;
You trying to copy by value. This is wrong because sibling points to nowhere. It is even not a NULL, it is unpredictable. The correct line will be:
sibling = p;
So you tell that would store pointer to another instance.
One notable problem is that you're returning by value in getSibling(), so you'll get a copy of the sibling rather than that actual sibling. Any changes you make will be to the temporary object.
As others have noted, you're addSibling function should be sibling = p. That's the source of your error.
But be sure to correct your getSibling function otherwise your setAddress won't do what you want.