(Beginner in OOP.)
I have a person class which stores the name of the person. In a derived class instance printer, I need that name so that I can do further tasks with it.
#include <iostream>
#include <string>
class Person{
public:
std::string name;
};
class Printer: public Person{
public:
void print(){
printf("%s", this->name.c_str());
}
};
int main() {
Person one;
one.name = "john";
Printer printer;
printer.print();
return 0;
}
What am I not doing to have printer see the data in one ? I'd be having several printer-like objects so storing "john" only once is the goal here.
You have made the member vars public but this is not the right approach for the OOP, the right one is to have them under private access specifier and use setters and getters.
Now to your mistakes:
You use void for main but with c++ you can only use int for it.
You use std::string as an argument for printf but it can't accept it. (I passed the c_string of the std::string to correct that).
You use an object, from the parent class, and give it a name then use another object, from the driven one, to print the name of the first one. (I used only one)
#include <iostream>
#include <string>
class Person{
public:
std::string name;
};
class Printer: public Person{
public:
void print(){
printf("%s",this-> name.c_str());
}
};
int main() {
Printer printer;
printer.name = "name";
printer.print();
}
After your comments, I have updated Printer class to do your inttent
#include <iostream>
#include <string>
class Person{
public:
std::string name;
};
class Printer{
public:
void print(const Person& person ){
printf("%s", person.name.c_str());
}
};
int main() {
Person one;
one.name = "name";
Printer printer;
printer.print(one);
}
Related
Hello so i want to create a header file class which name testing and also its cpp but for some reason this is inaccessible i dont know why
testing.h
#ifndef TESTING_H
#define TESTING_H
#include <string>
using namespace std;
class testing
{
string Name;
void printname(string name);
};
#endif
testing.cpp
#include <iostream>
#include "testing.h"
using namespace std;
void testing::printname(string name) // inaccessible in my main i dont know what reason :(
{
Name = name;
cout<<Name<<endl;
}
main
#include <iostream>
#include "testing.h"
using namespace std;
using std::string;
int main()
{
testing tester;
tester.printname("JPR"); //error since testing::printname is inaccessible no idea
return 0;
}
If you don't specify the visibility of the members, they are private.
You can either use a struct (visibility is public):
struct testing
{
string Name;
void printname(string name);
};
or you can specify that printname is public:
class testing
{
public:
void printname(string name);
private:
string Name;
};
Try the following:
testing.h
#ifndef TESTING_H
#define TESTING_H
#include <string>
class testing
{
public:
// Better to pass the parameter as const reference to avoid performing a copy.
void printname(const std::string& name);
private:
std::string Name;
};
#endif
testing.cpp
#include <iostream>
#include "testing.h"
void testing::printname(const std::string& name)
{
Name = name;
std::cout << Name << std::endl;
}
main.cpp
#include "testing.h"
int main()
{
testing tester;
tester.printname("JPR");
return 0;
}
In C++:
A class defined with the keyword class has private access for its members and its base classes by default.
Add public: access modifier to your class defition, to mark method as public:
class testing
{
string Name;
public:
void printname(string name);
};
when you create a class, every member function and member variable is set in default as private, which means that they won't be accessible. To make your function public you need to change this in your code:
class testing
{
private: //is private in default, i add it for better readabilty
string Name;
public:
void printname(string name);
};
Worth to mention that you (almost) ALWAYS want to keep all member variables private!
I have an abstract class called box that only has a string parameter called type and a virtual string that only returns that parameter. This class is the father of another class called Reward that has the constructor that fills the the parameter type and the same function of Box. I'm trying to put them in a class called Board that is basically a vector of the pointers of these classes, I have a constructor that just fills the vector with rewards. The problem comes that I compille it but doesn't run and I cannot find where is the problem. Thanks
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Box{
protected:
string type;
public:
virtual string getType()=0;
};
class Reward : public Box{
public:
string getType(){
return type;
}
Reward(){
type = "Reward";
}
};
class Board{
private:
vector<Box *> Table;
public:
Board(){
for (int i=0;i<=30;i++){
Table[i]=new Reward;
}
}
string getBoxes(int i){
return Table[i]->getType();
}
};
int main(){
Board game;
string toPrint=game.getBoxes(2);
cout<<toPrint;
return 0;
}
#include <iostream>
#include<string>
using namespace std;
class Human
{
private:
string Name;
int Age;
friend class Utility;
public:
Human(string InputName,int InputAge)
{
Name = InputName;
Age = InputAge;
}
};
class Utility
{
public:
void DisplayAge(const Human& Person)
{
cout<<Person.Age<<endl;
}
};
int main()
{
Human FirstMan("Adam",25);
cout<<"Accessing private member Age via friend class: ";
Utility::DisplayAge(FirstMan);
}
I don't understand..when I call the function I do send an object(FistMan)..why my compiler still says that I call it without object?
DisplayAge in Utility is not a static function. Therefore you need an instance of Uitility in order to call it.
So, either make the function static, or call it via an anonymous temporary
Utility().DisplayAge(FirstMan);
Better still, make DisplayAge a member function of Human.
Use the static keyword and then you'll be able to call your function on your class
I edited your code below :
#include <iostream>
#include<string>
using namespace std;
class Human
{
private:
string Name;
int Age;
friend class Utility;
public:
Human(string InputName,int InputAge)
{
Name = InputName;
Age = InputAge;
}
};
class Utility
{
friend class Human;
public:
Utility() = default;
static void DisplayAge(const Human& Person)
{
cout<<Person.Age<<endl;
}
};
int main(void)
{
Human FirstMan("Adam",25);
cout<<"Accessing private member Age via friend class: ";
Utility::DisplayAge(FirstMan);
}
Dön't use a class whenever you want to define functions. Use a namespace:
namespace Utility
{
inline void DisplayAge(const Human& Person)
{
cout<<Person.Age<<endl;
}
}
int main()
{
Human FirstMan("Adam",25);
cout<<"Accessing private member Age via friend class: ";
Utility::DisplayAge(FirstMan);
}
It s my 1st question but it s very improtant for me.
Language: C++, I would like to use
#include <list>
I have the abstract classes:
Organism.
Animal which inherits from Organism.
Plant which inherits from Organism.
Then I have classes like Wolf, Sheep, etc. They all inherit from Animal.
At the end I have classes like Oak, Grass, etc. They all inherit from Plant.
How can I create list having all those elements? list<Organism> my_list;
doesn't work.
In a big shortcut, you have to use polymorphism and your list should contain pointers of base type, which point to concrete objects.
For example:
#include <iostream>
#include <list>
#include <string>
using namespace std;
class Organism
{
public:
virtual string getName() const
{
cout<<"organism"<<endl;
return name;
}
protected:
string name;
};
class Animal : public Organism
{
public:
virtual string getName() const
{
cout<<"animal"<<endl;
return name;
}
};
class Plant : public Organism
{
public:
virtual string getName() const
{
cout<<"plant"<<endl;
return name;
}
};
int main() {
list<Organism*> objects;
Organism *ob1 = new Animal();
Organism *ob2 = new Plant();
objects.push_back(ob1);
objects.push_back(ob2);
for(auto it : objects)
{
it->getName();
}
for(auto it : objects)
{
delete it;
}
return 0;
}
I need to keep track of all objects created of a specific class and I need to access them using a identifier string. The following code does pretty much exactly what I need. The class NamedObject has a static member m_object_by_name, which maps the name (string) to the object, the constructor adds every created object to the map and the destructor removes deleted objects from the map.
#include <map>
#include <string>
#include <iostream>
using namespace std;
class NamedObject
{
public:
static NamedObject *object_by_name(const string &name) {
return m_object_by_name[name];
}
NamedObject(const string &name) : m_name(name) {
m_object_by_name[m_name] = this;
}
~NamedObject() {
m_object_by_name.erase(this->m_name);
}
const string &name() const{
return m_name;
}
private:
string m_name;
static map<string, NamedObject *> m_object_by_name;
};
map<string, NamedObject *> NamedObject::m_object_by_name;
int main ()
{
new NamedObject("name1");
new NamedObject("name2");
NamedObject *obj1 = NamedObject::object_by_name("name1");
NamedObject *obj2 = NamedObject::object_by_name("name2");
cout << obj1->name() << endl;
cout << obj2->name() << endl;
}
Now I have several classes whose objects need to be accessed by their name. Inheriting form the above NamedObject class of course has the problem that all these classes would share their names (e.g., I cannot have two objects of different classes but with the same name), as they share the map m_objects_by_name. Moreover, when accessing objects using the object_by_name() method, I always have to cast from NamedObject to the actual class.
The solution for this problem I use at the moment can be seen in the following code. However, I am not really satisfied with this solution (see comments below). The template class NamedObjectStore is now responsible for storing all objects of class T. Moreover, there is a base class handling the properties of having a name and a derived class that is really used. The derived class has a static NamedObjectStore object where it adds its objects on creation and removes them on deletion.
#include <map>
#include <string>
#include <iostream>
using namespace std;
template <class T>
class NamedObjectStore
{
public:
void add_object(T *obj) {
m_object_by_name[obj->name()] = obj;
}
void rem_object(T *obj) {
m_object_by_name.erase(obj->name());
}
T *object_by_name(const string &name) {
return m_object_by_name[name];
}
private:
map<string, T *> m_object_by_name;
};
class BaseNamedObject
{
public:
BaseNamedObject(const string &name) : m_name(name) {
}
const string &name() const {
return m_name;
}
private:
string m_name;
};
class DerivedNamedObject : public BaseNamedObject
{
public:
static NamedObjectStore<DerivedNamedObject> store;
DerivedNamedObject(const string &name) : BaseNamedObject(name) {
store.add_object(this);
}
~DerivedNamedObject() {
store.rem_object(this);
}
};
NamedObjectStore<DerivedNamedObject> DerivedNamedObject::store;
int main ()
{
new DerivedNamedObject("name1");
new DerivedNamedObject("name2");
DerivedNamedObject *obj1 = DerivedNamedObject::store.object_by_name("name1");
DerivedNamedObject *obj2 = DerivedNamedObject::store.object_by_name("name2");
cout << obj1->name() << endl;
cout << obj2->name() << endl;
}
On the positive side, the implementation of what makes an object a named object (i.e., the name()-function) is done in the base class BaseNamedObject. Also the implementation of the structure storing all objects lies in the NamedObjectStore class and is hidden behind its methods. This allows me to easily change both of these implementations if desired, without touching all the derived classes.
On the negative side, I still have to type the same stuff over and over again. More precisely, for every derived class (like DerivedNamedObject), I have to declare and to define the static member store, I have to add objects to the store in the constructor and remove them from the store in the destructor.
So here comes my question: is there a nicer way to solve this problem? Or do I just have to live with these four lines of code in every derived class?
Hoping for some inspiring suggestions :-)
Thomas
As stated in my comment, you can solve this using the curiously recurring template pattern. The code below uses your original example, templated on the type actually being stored:
#include <map>
#include <string>
#include <iostream>
using namespace std;
template<class T>
class NamedObject
{
public:
static NamedObject *object_by_name(const string &name) {
return m_object_by_name[name];
}
NamedObject(const string &name) : m_name(name) {
m_object_by_name[m_name] = this;
}
virtual ~NamedObject() {
m_object_by_name.erase(this->m_name);
}
const string &name() const{
return m_name;
}
private:
string m_name;
static map<string, NamedObject *> m_object_by_name;
};
template <class T>
map<string, NamedObject<T> *> NamedObject<T>::m_object_by_name;
class A : public NamedObject<A>
{
public:
A(const std::string& name) : NamedObject(name)
{}
};
class B : public NamedObject<B>
{
public:
B(const std::string& name) : NamedObject(name)
{}
};
int main()
{
new A("Test");
new B("Test");
auto one = A::object_by_name("Test");
auto two = B::object_by_name("Test");
cout << one << " - " << one->name() << "\n";
cout << two << " - " << two->name() << "\n";
delete two;
delete one;
}