Extending built-in classes in C++ - c++

I know extending built-in classes in C++ is deprecated, but still I want to do it for some reasons.
I wanna add my custom methods to a class (str) that extends/inherits from the std::string class (this is for an example)
But when I do so there's some problem I am facing with the methods that are already there in the std::string class (built-in methods), for example,
#include <bits/stdc++.h>
using namespace std;
class str : public string {
public:
string s;
str(string s1) {
s = s1; //ig the problem is here
}
};
int main() {
str s("hello world");
cout << s.size(); //prints out 0 not 11 => length of "hello world"
}
How do I get around this?

std::string doesn't know about your string s; member. It cannot possibly use it in its methods. If you want to use inheritance over composition, you need to use whatever is available under public interface of std::string - in this case, its constructors.
class str : public string {
public:
str(string s1): string(s1) //initialize base class using its constructor
{
}
};
// or
class str : public string {
public:
using string::string; //bring all std::string constructors into your class
};
As a footnote, there is nothing deprecated about inheriting from standard containers, but they are not meant for that and you can only do a very limited set of things safely. For example, this is Undefined Behaviour:
std::string* s = new str("asdf");
delete s; // UB!
More detailed explanation in this question.
Also, you should strongly avoid <bits/stdc++.h> and using namespace std; and in particular you should not mix them. You will strip yourself of almost every name and it produces hard to find bugs.

Related

how typeid(type).name() decide name for user define class? and can i change this behaviour?

i want to know for user define class how typeid(type) will decide the name for type of user define class check my below code for student class i got an output like 7Student but i don't understand why 7 is appended before Student class.
#include <iostream>
class Person {
protected:
std::string name;
public:
Person(std::string name)
: name(name) {}
};
class Student : public Person{
private:
std::string id;
public:
Student(std::string name,std::string id)
: id(id) , Person(name) {}
};
template<typename Type>
class Test {
private:
Type type;
public:
Test(Type type)
: type(type) {}
const char* getType() const {
return typeid(this->type).name();
}
};
int main() {
Test<int> *test1 = new Test<int>(5);
std::cout<<test1->getType()<<std::endl;
Test<float> *test2 = new Test<float>(1.1);
std::cout<<test2->getType()<<std::endl;
Test<double> *test3 = new Test<double>(1.1);
std::cout<<test3->getType()<<std::endl;
Test<long> *test4 = new Test<long>(11);
std::cout<<test4->getType()<<std::endl;
Test<unsigned int> *test5 = new Test<unsigned int>(11);
std::cout<<test5->getType()<<std::endl;
Test<Student> *test6 = new Test<Student>(*(new Student("visrut","111")));
std::cout<<test6->getType()<<std::endl; // 7Student
Test<Person> *test7 = new Test<Person>(*(new Person("visrut")));
std::cout<<test7->getType()<<std::endl;
Test<std::string> *test8 = new Test<std::string>("visrut");
std::cout<<test8->getType()<<std::endl;
return 0;
}
i tried this code with extend Person class and without extend Person class but output is same for last type and it is 7Student.
for your reference on my g++ compiler output is below
i
f
d
l
j
7Student
6Person
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Now when i tested for Person class also it's output is 6Person so i found this behaviour as {length of user-define class}{class-name} but i got weird output for std::string so i want to ask can i change this behaviour in Person or Student class is there is something built in method i can write in Person or Student class that return specific const char * for typeid().name() ?
The name() member of std::type_info is totally implementation defined. You cannot change what is output, and it is not known what will be output. It may even be different between runs.
Returns an implementation defined null-terminated character string containing the name of the type. No guarantees are given; in particular, the returned string can be identical for several types and change between invocations of the same program.
From here.
If you need to define and retrieve a specific name from a class, you are looking at doing something called reflection (or a very simply form of it). This is not something that c++ was designed for and you should avoid relying on needing to do this if you can. IF you find you really need to do it, you can find more info at How can I add reflection to a C++ application?.

How come accessing derived class member in base class pointer vector returns an error?

Streamlined Example of the problem:
#include <string>
#include <deque>
#include <iostream>
class Action{
public:
std::string name;
Action(std::string name){
this->name = name;
}
};
class Ability : public Action{
public:
int bar;
Ability(std::string name) : Action(name){}
};
int main(){
std::deque<Action*> foo;
Ability test("asdf");
test.bar = 122;
foo.push_back(&test);
std::cout << foo.at(0)->bar << std::endl;
return 0;
}
This creates an error, that there is no 'bar' member of 'Action'.
I realise that this relates to object slicing and I've attempted to use pointers, which allows the vector to push back the 'Ability' object but I cannot access its 'bar' member.
What am I missing?
First, a word from our sponsor: What is object slicing?
Now that you've read the above link, you can see that no slicing has taken place because the object was not copied into foo, only a pointer to the object was copied. The Ability is still intact, wherever in memory test sits.
But... Foo contains pointers to Action, not Ability. There is no way for a user of Foo to know if any given element of Foo is a reference to an Action, an Ability, or some other subclass of Action that they know absolutely nothing of. Very powerful stuff, the ability to work with something you don't even know exists, but this comes at a price: You have to work with it as something you do know. Users of Foo can only use the interface presented to them, that of Action. There are ways around this, such as dynamic_cast, but in most cases it best to stick with the provided interface and allow an overloaded method or operator to do black magic behind the scenes to do the correct thing for whatever the Action represents. If this means you have to
class Action{
public:
std::string name;
Action(std::string name){
this->name = name;
}
virtual int getbar() = 0; // pure virtual method that all subclasses
// of Action must implement
};
class Ability : public Action{
public:
int bar;
Ability(std::string name) : Action(name){}
int getbar()
{
return bar;
}
};
and later
std::cout << foo.at(0)->getbar() << std::endl;
so be it.

task list in C++ (vector with more than one type)

My aim is to fill a list of task; each will be an object containing the description of the task. Let'say there will be only two type of tasks : file copy and repertory copy.
Since a vector cannot contain more than one type of objects, I though to create a generic task class and two classes that inheritate from that one.
Here is the code :
#include <iostream>
#include <deque>
#include <string>
using namespace std;
class GenericTask{
public :
string config;
GenericTask(string s){
config=s;
}
void run(){
cout<<"Running generic task" <<endl;
}
};
class FileCopyTask : public GenericTask{
public:
string filename;
FileCopyTask(string cf,string fn):GenericTask(cf)
{
filename=fn;
}
void run(){
cout<<"file :"<<filename<<endl;
}
};
class RepertoryCopyTask : public GenericTask{
public:
string repname;
RepertoryCopyTask(string cf,string rn):GenericTask(cf)
{
repname=rn;
}
void run(){
cout<<"repertory : "<<repname<<endl;
}
};
void run_next(deque<GenericTask> &task_list){
task_list.front().run();
task_list.pop_front();
}
int main()
{
RepertoryCopyTask rtask("configuration","/home");
FileCopyTask ftask( "configutation","gile.tex" );
deque<GenericTask> task_list;
task_list.push_back(rtask);
task_list.push_back(ftask);
run_next(task_list);
}
As it, it does not work because run_next expect a GenericTask and both rtask and ftask are treated as generic.
How should I do ?
I already tried to add template here and there, but ultimately it does not work because I need to know the type inside the deque before to "extract" something.
Can I consider this as an answer ?
Why not create objects of FileCopyTask and RepertoryCopyTask and save them as pointers to GenericTask? This way you can leverage the power of runtime polymorphism.
Like this:
int main()
{
std::unique_ptr<GenericTask> ftask = std::make_unique<FileCopyTask>("configutation","gile.tex");
std::unique_ptr<GenericTask> rtask = std::make_unique<FileCopyTask>("configuration","/home");
...
}
void run_next(deque<std::unique_ptr<GenericTask> > &task_list)
{
....
}
Also, do not forget to mark the run() method in class GenericTask as virtual. Also provide a virtual destructor.
I made some changes in your source. Defined your base fn as virtual and stored objects with pointers. You can check it below.
#include <iostream>
#include <deque>
#include <string>
using namespace std;
class GenericTask{
public :
string config;
GenericTask(string s){
config=s;
}
virtual void run(){
cout<<"Running generic task" <<endl;
}
};
class FileCopyTask : public GenericTask{
public:
string filename;
FileCopyTask(string cf,string fn):GenericTask(cf)
{
filename=fn;
}
void run(){
cout<<"file :"<<filename<<endl;
}
};
class RepertoryCopyTask : public GenericTask{
public:
string repname;
RepertoryCopyTask(string cf,string rn):GenericTask(cf)
{
repname=rn;
}
void run(){
cout<<"repertory : "<<repname<<endl;
}
};
void run_next(deque<GenericTask*> &task_list){
task_list.front()->run();
task_list.pop_front();
}
int main()
{
RepertoryCopyTask* rtask = new RepertoryCopyTask("configuration","/home");
FileCopyTask* ftask = new FileCopyTask( "configutation","gile.tex" );
deque<GenericTask*> task_list;
task_list.push_back(ftask);
task_list.push_back(rtask);
run_next(task_list);
}
How should I do ?
Consider these steps:
define GenericTask as a base class (add virtual destructor, make void run virtual)
override the run function in derived classes
store elements in the queue as std::unique_ptr, instead of "by value" to avoid the slicing problem.
I already tried to add template here and there, but ultimately it does not work because I need to know the type inside the deque before to "extract" something.
You can add a boost::variant as the value, allowing the storage of unrelated types.
Can I consider this [this=answer proposing boost::any as value type] as an answer ?
Yes. boost::variant would be similar (the difference is that boost::any supports setting any value; boost::variant only supports values of the types provided as variant arguments).
A classical case of virtual. The run methods need to be declared virtual s.t. you are actually calling RepertoryCopyTask::run() on an object of type GenericTask.
When done correctly,
FileCopyTask t("a", "b");
GenericTask & g = t;
g.run();
will call FileCopyTask::run instead of GenericTask::run (which it would in the original question).
When you did this, you can't store your FileCopyTasks and RepertoryCopyTask in a contaianer for GenericTask. This is because they might even have different size. To get around this, you should store unique_ptrs for them in some container, i.e.
std::vector<std::unique_ptr<GenericTask> > tasks;
This would be the correct way of solving your problem.

Classes, Privates through Publics

i am trying to understand how can i access private classes through public classes because some experts said to me that i have to use only private classes. But i can't understand why this doesn't work.I really don't know how can i access private through public its really confusing .
#include <iostream>
#include <string>
using namespace std;
class ManolisClass{
public :
void setName(string x){
name = x;
}
string getName(){
return name;
}
private :
string name;
};
int main()
{
ManolisClass bo;
getline(cin, bo.setName() );
cout << bo.getName();
return 0;
}
Your access methods are correct, but as you can see from the signature of the function setName, you have to provide a string to set the name of the class. getLine method takes a string as argument. You could create an intermediate variable and use that variable to set the name of the class.
Here is how one can do it.
string temp;
getline(cin, temp);
bo.setName(temp);

Accessing C++ classes based on list of strings

I am hoping this is possible in C++.
I have a list of classes that inherit from a common base class (Base). All of these will be compiled as part of the library linked to my program.
I could be adding more classes that derive from Base and will be recompiling everything after I do this.
When my program starts it will gather a vector of all classes (using some preprocessing method I have already implemented) that implement from Base.
What I want to do (you have probably guessed by now) is to create objects from these classes just based on the string names. Is this possible?
Regards
Mark
Well, if you have a preprocessed list of all classes then you can create a construction object that will "know" each of those classes and will construct (by manually searching through the list) them upon request.
Depends on what you're trying to do. There are probably better ways to do what you need to do but here's an oversimplified example...
#include <string>
using namespace std;
class b1{};
class d1 : public b1{};
class d2 : public b1{};
...
int main(int argc, char* argv[]) {
string name(argv[1]);
b1* b;
if (name == "d1")
b = new d1;
else if (name == "d2")
b = new d2;
}
Sure, but not the way you would like. C++ has no reflection, so you have to build the mechanism yourself: (See below for EDIT which implements a map of factory pointers)
#include <string>
#include <vector>
#include <memory>
using namespace std;
class Base
{
};
class Dog : public Base
{
};
class Cat : public Base
{
};
int main()
{
typedef vector<string> strings;
strings names;
names.push_back("Dog");
names.push_back("Cat");
names.push_back("Dog");
names.push_back("Cat");
typedef vector<Base*> Bases;
Bases my_objs;
for( strings::const_iterator it = names.begin(), it_end = names.end(); it != it_end; ++it )
{
if( *it == "Dog" )
my_objs.push_back(new Dog);
else if( *it == "Cat" )
my_objs.push_back(new Cat);
}
}
EDIT:
Any solution you come up with in C++ is going to be fundamentally some variation of the above. One common variation is to try to get rid of the if block by doing some kind of lookup. This can be implemented using a map object which links the name of the object to a function that instantiates it. One thing to note about this approach is that the function pointers in the map have to have the same signature, meaning theDog and Cat factory methods have to take the same number and type of parameters. This is a problem that can be solved using Boost::Any (link) or other heroic methods, but that's beyond the scope of this post.
Here's a solution that implements a map of factory method pointers:
#include <string>
#include <vector>
#include <map>
using namespace std;
class Base
{
public:
virtual ~Base() {};
};
class Dog : public Base
{
public:
static Base* make_dog() { return new Dog; }
};
class Cat : public Base
{
public:
static Base* make_cat() { return new Cat; }
};
typedef Base*(*ObjFactoryFn)();
typedef map<string, ObjFactoryFn> Factories;
int main()
{
// set up the map of object factory pointers
Factories factories;
factories["Dog"] = &Dog::make_dog;
factories["Cat"] = &Cat::make_cat;
// build list of objects we want
typedef vector<string> strings;
strings names;
names.push_back("Dog");
names.push_back("Cat");
names.push_back("Dog");
names.push_back("Cat");
// build objects using the factory map
for( strings::const_iterator it = names.begin(), it_end = names.end(); it != it_end; ++it )
{
// construct
Base* my_obj = factories[*it](); // this should use map's "find" method for robustness
// destroy
delete my_obj;
}
}