Weird behavior with OOP and string pointers - c++

Here's my code:
#include <iostream>
#include <string>
class Human
{
public:
std::string * name = new std::string();
void introduce();
};
void Human::introduce()
{
std::cout << "Hello, my name is " << Human::name << std::endl;
}
int main()
{
Human * martha;
martha->name = new std::string("Martha");
martha->introduce();
return 0;
}
Well, it's supposed to print a message out like:
"Hello, my name is Martha" but it doesn't print neither the "Hello, my name is" string or the "Martha" name. Why does it occur?

The fix is simple and is to completely remove all pointers; see the code below. There are a number of issues with your code that I could address in detail, including memory leaks, uninitialized variables, and general misuse of pointers, but it seems that you're possibly coming from a different language background and should spend time learning good practice and the important semantics and idioms in modern C++ from a good C++ book.
#include <iostream>
#include <string>
class Human
{
public:
std::string name;
void introduce();
};
void Human::introduce()
{
std::cout << "Hello, my name is " << name << std::endl;
}
int main()
{
Human martha;
martha.name = "Martha";
martha.introduce();
return 0;
}

Few modifications are required to the code.
Updated code along with the comments to the change made are included below.
#include <iostream>
#include <string>
class Human
{
public:
//Removed pointer to a string
//Cannot have an instantiation inside class declaration
//std::string * name = new std::string();
//Instead have a string member variable
std::string name;
void introduce();
};
void Human::introduce()
{
//Human::name not required this is a member function
//of the same class
std::cout << "Hello, my name is " << name << std::endl;
}
int main()
{
Human *martha = new Human();
//Assign a constant string to string member variable
martha->name = "Martha";
martha->introduce();
return 0;
}
As suggested by #alter igel - The Definitive C++ Book Guide and List would be a good place to start.

#include <iostream>
#include <string>
class Human {
public:
void Human(std::string* n) { name = n; }
void introduce();
private:
std::string* name;
};
void Human::introduce() {
std::cout << "Hello, my name is " << name << std::endl;
}
int main() {
Human* martha = new Human(new std:string("Martha"));
martha->introduce();
return 0;
}
Try that. The difference is that you don't initialise the variable in the class definition, and you initialise the name with the constructor. You can split the method definition out into it's own section, but it's only one line and is fine being inside the class definition.

Related

Struggling with pointers to functions and references

I am working through this problem I found on Git to brush up on some skills. Using friend is prohibited. C++ styling should be used compared to C.
Essentially, I cannot call the identify() function that belongs to the Brain member variable in my Human class. It just will not let me access it. If you can code this up, and explain where I am going wrong, that would be great.
Create a Brain class, with whatever you think befits a brain. It will have an Identify() function that returns a string containing the brain's address in memory, in hex format, prefixed by 0x.
Then, make a Human class, that has a constant Brain attribute with the same lifetime. It has an identify() function, that just calls the identity() function of its Brain and returns its result.
Now, make it so this code compiles and displays two identical addresses:
int main(){
Human bob;
std::cout << bob.identify() << "\n";
std::cout << bob.getBrain().identify() << "\n";
}
Here is what I have so far:
#pragma once
#include "Brain.h"
class Human
{
const Brain humanBrain;
public:
Human();
std::string identify();
};
#include "Human.h"
#include <iostream>
#include <string>
#include <sstream>
Human::Human()
{
this->humanBrain = new Brain;
}
std::string Human::identify()
{
Brain b = this->humanBrain.identify(); // This is essentially what I am trying to call--and I can't access it.
const Brain * ptr = humanBrain;
std::ostringstream test;
test << ptr;
return test.str();
}
#pragma once
#include <string>
#include <iostream>
class Brain
{
int age;
std::string gender;
void* ptr;
public:
Brain();
//std::string getBrain();
const std::string identify();
void setPtr(void* p);
};
#include "Brain.h"
#include <iostream>
#include <sstream>
Brain::Brain()
{
age = 10;
gender = "male";
}
const std::string Brain::identify()
{
//const Brain* bPtr = &this;
const Brain* bPtr = this;
ptr = this;
std::ostringstream test;
test << &bPtr;
std::string output = "Brain Identify: 0x" + test.str();
return output;
}
Your Human::humanBrain member is declared as type const Brain, which is correct per the instructions, however your Brain::identify() method is not qualified as const, so you can't call it on any const Brain object. This is the root of the problem that you are having trouble with.
In addition, there are many other problems with your code, as well:
Human::humanBrain is not a pointer, so using new to construct it is wrong. And, you don't need a pointer to get the address of a variable anyway. Nor do you actually need a pointer to the member at all in this project.
Human lacks a getBrain() method, so bob.getBrain() in main() will not compile, per the instructions.
Human::identify() is calling humanBrain.identify(), which returns a std::string as it should, but is then assigning that string to a local Brain variable, which is wrong (not to mention, you are not even using that variable for anything afterwards). The instructions clearly state that Human::identity() should simply call Brain::identify() and return its result, but you are not doing that.
Brain::identify() is printing the address of its local variable bPtr rather than printing the address of the Brain object that identify() is begin called on, per the instructions.
With all of that said, try something more like this instead:
Human.h
#pragma once
#include "Brain.h"
#include <string>
class Human
{
const Brain humanBrain;
public:
Human() = default;
std::string identify() const;
const Brain& getBrain() const;
};
Human.cpp
#include "Human.h"
std::string Human::identify() const
{
return humanBrain.identity();
}
const Brain& Human::getBrain() const
{
return humanBrain;
}
Brain.h
#pragma once
#include <string>
class Brain
{
int age;
std::string gender;
public:
Brain();
std::string identify() const;
};
Brain.cpp
#include "Brain.h"
#include <sstream>
Brain::Brain()
{
age = 10;
gender = "male";
}
std::string Brain::identify() const
{
std::ostringstream test;
test << "Brain Identify: 0x" << this;
return test.str();
}

How to implement a class that has one of either two types for an arg

if I have a c++ class like:
class Student
{
public:
string name;
int assigned_number;
};
and I want to use either name or number but not both for each instance, is there a way to make this an Or type where only one of them is required?
If you are using C++17 or above, you can use std::variant from <variant>:
#include <iostream>
#include <variant> // For 'std::variant'
class Student
{
public:
std::variant<std::string, int> name_and_id;
};
int main() {
Student stud; // Create an instance of student
// Pass a string and print to the console...
stud.name_and_id = "Hello world!";
std::cout << std::get<std::string>(stud.name_and_id) << std::endl;
// Pass an integer and print to the console...
stud.name_and_id = 20;
std::cout << std::get<int>(stud.name_and_id) << std::endl;
}
std::variant is a new addition to C++17 and is intended to replace the unions from C and has exceptions in case of errors...
You can use union.
#include <string>
class Student
{
// Access specifier
public:
Student()
{
}
// Data Members
union
{
std::string name;
int assigned_number;
};
~Student()
{
}
};
int main()
{
Student test;
test.assigned_number = 10;
test.name = "10";
return 0;
}

Struggling with C++ "was not declared in this scope"

Can anyone tell me why i get the error "name was not declared in the scope when running this?
Thanks.
class lrn11_class{
public:
void setName(string x){
name = x;
}
string getName(){
return name;
}
private:
string lrn11_name;
};
int main()
{
lrn11_class lrn11_nameobject;
lrn11_nameobject.setname("Zee");
cout << lrn11_nameobject.getname() << endl;
return 0;
}
This should work - see comments (BTW use std:: - Why is "using namespace std" considered bad practice?)
#include <iostream>
#include <string>
class lrn11_class{
public:
void setName(const std::string& x){ // Potentially saves copying overhead
name = x;
}
std::string getName() const { // Look up const and its uses
return name;
}
private:
std::string name; // - Used: string lrn11_name; but functions use name!
};
int main()
{
lrn11_class lrn11_nameobject;
lrn11_nameobject.setName("Zee"); // Fixed typo
std::cout << lrn11_nameobject.getName() << std::endl; // Ditto
return 0;
}
You have declare lrn11_name as a member varible for this class. But in set and get functions you are using name.
Other than than you need to call functions as you have defined.
so instead of :-
lrn11_nameobject.setname("Zee");
cout << lrn11_nameobject.getname() << endl;
You have to use following code :-
lrn11_nameobject.setName("Zee");
cout << lrn11_nameobject.getName() << endl;
Make sure that
#include <iostream>
using namespace std;
should be included.

Is it possible to call a method from an instance that doesn't exist?

The code I'm working on :
I had the following code (with an error about the index in main.cpp) :
Sample.hpp :
#ifndef SAMPLE_HPP
# define SAMPLE_HPP
# include <iostream>
# include <string>
class Sample{
public:
Sample(void);
~Sample(void);
void tellname(void) const;
private:
std::string _name;
};
#endif
Sample.cpp :
#include <iostream>
#include "Sample.hpp"
Sample::Sample(void){
this->_name = "testname";
return;
};
Sample::~Sample(void){
return;
}
void Sample::tellname(void) const{
std::cout << "Name : " << this->_name << std::endl;
return;
}
main.cpp
#include "Sample.hpp"
int main(void){
int i;
Sample *test;
test = new Sample[4];
i = 0;
while (i++ < 4) // I know : i++; shouldn't be here
test[i].tellname();
delete [] test;
return 0;
}
If I compile this I get the following output :
Name : testname
Name : testname
Name : testname
Name :
My question is :
About the last line, it calls a method (void Sample::tellname(void)) but from an instance that is not in the range of the table (test[4] doesn't exist).
However, it still calls tellname() even the instance it calls it from doesn't exist. It just considers its _name field being empty.
How is this possible?
It's simply undefined behavior, something C++ imposes no requirements on so "anything could happen". What you're seeing is just a coincidence and worthless to reason about: next time you run it could crash, display nyan cat and so on.
It sounds like you are wondering why the function is called. In memory, structs do not contain the functions inside them. Instead, one copy of the functions are placed somewhere in the executable. So when you are calling test[4].tellname() what is really happening is: The address test + (4 * sizeof(Sample)) is passed to the function tellname(). The value at that address is undefined.
Here is an example to give you an idea of what is going on:
#include <iostream>
struct astruct {
int i = 0;
void prnt()
{
std::cout << i << '\n';
}
};
struct bstruct {
int y = 100;
};
int main()
{
bstruct b;
((astruct*)&b)->prnt();
getchar();
return 0;
}
Here prnt() is behind the scenes being passed the address of bstruct and treats it like the address of an astruct, since the first value in bstruct is 100, it prints 100. You can even simplify it to this:
#include <iostream>
struct astruct {
int i = 0;
void prnt()
{
std::cout << i << '\n';
}
};
int y = 100;
int main()
{
((astruct*)&y)->prnt();
getchar();
return 0;
}
i goes from 1 to 4 include, since tellname is const, test[4].tellname() is Sample::tellname with Sample being an undefined structure so "Name :" is rightfully printed then the memory in test[4]._name is printed and luckily the memory pointed by test[4]._name* is non null and is even a end string char.
So yeah you are lucky.

destructor ignore string assignment

I have created a program in C++ for a class, and one of the requirements is to output a string when certain parts of the program have been called. For most of these I have simply assigned a string to a member variable and then outputted that variable. I wanted to know is it possible for me to assign the string in a destructor and then output that string? When I try it, it outputs nothing.
ie:
Class
private:
string output;
~Class {
output = "destructor has fired!";
}
int main(){
cout << class.message;
}
This is pseudocode so please ignore syntax mistakes/missing pieces.
It certainly is possible to output a message in the destructor, to know that it has fired, and one way to do it is this...
#include <iostream>
#include <string>
using namespace std;
class C{
string output; // by default private
public:
C(){}
~C() { cout << output << endl; }
void setString(const string& s) {
output = s;
}
};
int main()
{
{
C s;
s.setString("Destructor has fired");
}
return 0;
}
If I understand your question right, this is what you are expected to do. Note: no member variable, direct calls to std::cout.
#include <iostream>
#include <string>
using namespace std;
class C{
public:
C() {
cout << "C ctor" << endl;
}
~C() {
cout << "C dtor" << endl;
}
};
int main()
{
{
C s;
}
return 0;
}