I have a abstract class named Base from which I derived a class(Derived) as follows:
#include <iostream>
#include <string>
#include <memory>
class Base
{
public:
virtual void printClass()const = 0;
virtual ~Base(){}
};
class Derived: public Base
{
private:
int m_var1;
std::string m_var2;
public:
Derived() = default;
Derived(const int& v1, const std::string& v2)
:m_var1(v1), m_var2(v2)
{ }
void printClass()const override
{
std::cout << "Derived Class with\t";
std::cout << m_var1 << " " << m_var2 << std::endl;
}
~Derived(){ std::cout << "Derived destroyed" << std::endl; }
};
Now in the main() to make use of polymorphisum I could declare as follows:
int main()
{
std::shared_ptr<Base> Obj[3];
Obj[0] = std::make_shared<Derived>(1,"One");
Obj[1] = std::make_shared<Derived>(2,"Two");
Obj[2] = std::make_shared<Derived>(3,"Three");
for(const auto& it: Obj)
it->printClass();
return 0;
}
However, I am currently trying to learn more about the std::shared_ptr<>() and its custom deletion technics and I came across following statement.
std::shared_ptr<Base> Obj(new Derived[3], [](Derived* obj){ delete[] obj; });
and
std::shared_ptr<Base> Obj(new Derived[3] = {
{1,"One"},
{2,"Two"},
{3,"Three"}
},
[](Derived* obj){ delete[] obj; });
My questions are:
Why I can not initialize or pass values to the constructor of Derived class in following manner, even-though I have a costume defined constructor available for the derived class? or am I missing something?
If so what would be the correct way of initializing and accessing
such array of derived class elements?
You can call the constructor like this:
std::shared_ptr<Base> Obj{
new Derived[3]{ {1,"One"}, {2,"Two"}, {3,"Three"} },
[](Derived* obj){ delete[] obj; }
};
Related
What is the easiest way to create an object on stack based on a certain condition within the current scope?
Assume my current code is:
Base obj();
obj.print();
Now I want to change the code to 'plugin' a different derived class e.g. :
bool doBase=true;
doBase ? Base obj() : Derived obj();
obj.print();
But this of course does not work?
I know how to get this working, e.g. with an if, however my print in this example is in real world say 10-50 lines so this result in code duplication. Another approach is dynamically creating the objects, but I am curious there is a way to fix this without dynamically creating the objects.
bool doBase=true;
if (doBase) {
Base obj();
obj.print();
} else {
Derived obj();
obj.print(); // CODE DUPLICATION
}
Full snippet:
#include <iostream>
class Base {
virtual void print() { std::cout << "In base"<<std::endl; }
};
class Derived : public Base {
virtual void print() override { std::cout << "In derived"<<std::endl; }
};
int main() {
bool doBase=true;
doBase ? Base obj() : Derived obj();
obj.print();
doBase=false;
doBase ? Base obj2() : Derived obj2();
obj2.print();
}
You could use lambdas to wrap the repetitive code, eg:
#include <iostream>
class Base {
public:
virtual void print() { std::cout << "In base"<<std::endl; }
};
class Derived : public Base {
public:
virtual void print() override { std::cout << "In derived"<<std::endl; }
};
int main() {
auto print = [](Base &&obj){ obj.print(); };
auto doIt = [&print](bool doBase) { doBase ? print(Base{}) : print(Derived{}); };
doIt(true);
doIt(false);
}
Online Demo
Alternatively, use std::variant, eg:
#include <iostream>
#include <variant>
class Base {
public:
virtual void print() { std::cout << "In base"<<std::endl; }
};
class Derived : public Base {
public:
virtual void print() override { std::cout << "In derived"<<std::endl; }
};
int main() {
auto print = [](Base& obj){ obj.print(); };
auto doIt = [&print](bool doBase) {
std::variant<Base, Derived> v;
if (doBase) {
v = Base{};
} else {
v = Derived{};
}
std::visit(print, v);
};
doIt(true);
doIt(false);
return 0;
}
Online Demo
I was translating a Java program of mine to C++. I got to a problem trying to use polymorphism the same way as in Java.
My code looks something like this:
class Base
{
public:
virtual void print() = 0;
};
class Derived_1 : public Base
{
public:
void print()
{
std::cout << "1" << std::endl;
}
};
class Derived_2 : public Base
{
public:
void print()
{
std::cout << "2" << std::endl;
}
};
The next are two versions of my main method that I have tried, both give me compiler errors:
1:
int main(int argc, char const *argv[])
{
std::vector<Base> v;
v.push_back(Derived_1());
v.push_back(Derived_2());
for(Base i: v)
{
i.print();
}
return 0;
}
Error:
object of abstract class type "Base" is not allowed:C/C++(322)
main.cpp(35, 14): function "Base::print" is a pure virtual function
2:
int main(int argc, char const *argv[])
{
std::vector<Base*> v;
v.push_back(new Derived_1());
v.push_back(new Derived_2());
for(Base* i: v)
{
i.print();
}
return 0;
}
Error:
expression must have class type but it has type "Base *"C/C++(153)
How would you guys solve this?
Coming from java to c++, there are a lot to take-care; Especially memory management!
In your first shown case, you are slicing the objects. See What is object slicing?
In order to access the virtual functions, you should have used std::vector<Base*> (i.e. vector of pointer to Base), or std::vector<std::unique_ptr<Base>> or std::vector<std::shared_ptr<Base>>(i.e. vector of smart pointer to Base).
In your second shown code, your v is a vector of pointer to Base, meaning you need to access the members via the -> operator.
i.e. You should have accessed the print() as follows:
i->print();
^^^
Or alternatively:
(*i).print();
^^^^^
Also note that:
In your second case, whatever you newed must be deleted, so that the program doesn't leak memory. Alternately, we have smart memory management
The Base is missing a virtual destructor, which will lead to undefined behavior when deleteing the ovjects. You should add one for defined behavior. See: When to use virtual destructors?
Using std::unique_ptr, your code will look like (example code):
#include <memory> // std::unique_ptr, std::make_unique
class Base
{
public:
virtual void print() /* const */ = 0;
// add a virtual destructor to the Base
virtual ~Base() = default;
};
class Derived_1 : public Base
{
public:
void print() override /* const */ {
std::cout << "1" << std::endl;
}
};
class Derived_2 : public Base
{
public:
void print() override /* const */ {
std::cout << "2" << std::endl;
}
};
int main()
{
std::vector<std::unique_ptr<Base>> v;
v.reserve(2); // for unwanted re-allocations of memory
v.emplace_back(std::make_unique<Derived_1>());
v.emplace_back(std::make_unique<Derived_2>());
for (const auto& i : v) // auto == std::unique_ptr<Base>
{
i->print();
}
return 0;
}
i need to call the overidden function inside B class through C class but it gives "Base" as a output rather than "Derived". when I call this code part classC.getTargetB().example(); i need to get "Derived" as a output. how can i reach my goal in the code.
class A {
public:
A() {};
virtual void example() { std::cout << "Base" << std::endl; }
};
class B :public A {
protected:
std::string name;
public:
B() {};
B(std::string n) { name = n; }
void example() override { std::cout << "Derived" << std::endl; }
};
class C {
protected:
std::vector<std::shared_ptr<A>> ptr;
std::shared_ptr<A> targetBobject;
public:
void setB(std::shared_ptr<A> target) {
targetBobject = target;
}
A getTargetB() {
return *targetBobject;
}
};
int main()
{
A example;
std::vector<std::shared_ptr<A>> parent;
C classC;
std::shared_ptr<B> ptr1 = std::make_shared<B>("B1");
std::shared_ptr<B> ptr2 = std::make_shared<B>("B2");
parent.push_back(std::move(ptr1));
parent.push_back(std::move(ptr2));
//parent.at(0)->example(); this gives 'Derived' as a output
classC.setB(parent.at(0));
classC.getTargetB().example();// gives 'Base' as a output
}
I would like to create a base class ==> derived class setup where the base class' constructor has a callback to run a (possibly complex) function to modify the base class' private member with information from the derived class. However, I'm running into a chicken and an egg problem because the base class constructor runs before the derived class' members are initialized. Here's the code to demonstrate the problem:
#include <iostream>
#include <functional>
class B
{
public:
typedef std::function<void(std::string &)> mod_func_t;
B(const mod_func_t &m) : foo("base str")
{
std::cout << "Base constructor\n";
m(foo);
std::cout << "base constructor finally has: " << foo << std::endl;
}
private:
std::string foo;
};
class D : public B
{
public:
D(const std::string &input) :
B(std::bind(&D::my_f, this, std::placeholders::_1)),
input_(input)
{
std::cout << "Derived constructor\n";
}
private:
void my_f(std::string &s)
{
std::cout << "Derived class' modification function\n";
s += input_; // <== Crashes here because input_ is not yet constructed
}
const std::string input_;
};
int main()
{
D d("my input");
return 0;
}
What is the correct way to do this?
One approach is to let D calculate the adjusted string before calling the constructor of B.
class D : public B {
D(std::string str)
: B(my_f(str))
{}
std::string my_f(std::string str) { return str + "..."; }
};
A second approach is to let the body of constructor D do some work. Here adjust_base could also be virtual.
class D : public B {
D(std::string str)
: B(str)
{
adjust_base();
}
void adjust_base();
};
I believe that CRTP could help you with this one..
There is a simple example:
#include <iostream>
#include <functional>
template <typename Derived>
class B
{
public:
B() : foo("base str")
{
static_cast<Derived*>(this)->m(foo);
std::cout << "Base constructor\n";
std::cout << "base constructor finally has: " << foo << std::endl;
}
void m(std::string& str) { //... }
private:
std::string foo;
friend Derived;
};
class D : public B<D>
{
public:
D(std::string &input) :
B(),
input_(input)
{
std::cout << "Derived constructor\n";
}
void m(const std::string& str) { //... }
private:
void my_f(std::string &s)
{
std::cout << "Derived class' modification function\n";
s += input_; // <== Crashes here because input_ is not yet constructed
}
const std::string input_;
};
int main()
{
D d("my input");
return 0;
}
I'm wondering if it's possible to create a map of pointers of inherited classes. Here's an example of what I'm trying to do:
#include <string>
#include <map>
using namespace std;
class BaseClass
{
string s;
};
class Derived1 : public BaseClass
{
int i;
};
class Derived2 : public Derived1
{
float f;
};
// Here's what I was trying, but isn't working
template<class myClass>
map<string, myClass>m;
int main()
{
// Add BaseClasses, Derived1's, and/or Derived2's to m here
return 0;
}
The errors I get are:
main.cpp(23): error C2133: 'm' : unknown size
main.cpp(23): error C2998: 'std::map<std::string,myClass>m' : cannot be a template definition
I get why I'm getting this error, but I'm wondering if it's possible to create a map that can hold different levels of inherited classes? If not, is it possible to create some sort of management system that can hold various class types? Or would I have to make different maps/vectors/arrays/etc. for each type of class?
Yes you can store inherited classes in map, but pointers to them, not objects themselves. Here's a short example (it lacks memory management on pointers)
#include <iostream>
#include <string>
#include <map>
#include <utility>
using namespace std;
class BaseClass
{
string s;
public:
BaseClass() { s = "BaseClass";}
virtual void print()
{
cout << s << std::endl;
}
};
class Derived1 : public BaseClass
{
int i;
public:
Derived1() { i = 10; }
void print()
{
cout << i << std::endl;
}
};
class Derived2 : public Derived1
{
float f;
public:
Derived2() { f = 4.3;}
void print()
{
cout << f << std::endl;
}
};
int main()
{
map<string, BaseClass*>m;
m.insert(make_pair("base", new BaseClass()));
m.insert(make_pair("d1", new Derived1()));
m.insert(make_pair("d2", new Derived2()));
m["base"]->print();
m["d1"]->print();
m["d2"]->print();
return 0;
}
First things first:
template<class myClas>
map<string, myClass> m;
This is not valid C++ and could only mean something like a template alias, but I believe, that is not what you are looking for.
Storing polymorphic objects in C++ is complicated by slicing (constructing a value of the base type from a value of a derived type). Dynamic polymorphism can only be handled through references or pointers. You could potentially use std::ref or boost::ref for situations in which the map will only be passed down the callstack, but this requires some care. Often, storing pointers to the base is the way to go: std::map<std::string, base*>. Managing deallocation yourself is rather tedious and either std::map<std::string, std::unique_ptr> or std::map<std::string, std::shared_ptr> are preferred, depending if you need shared semantics or not.
Basic example. Someone should replace this with something more meaningful.
#include <memory>
#include <string>
#include <map>
#include <iostream>
class animal
{
public:
virtual ~animal() {};
virtual void make_sound() const = 0;
};
class dog : public animal
{
public:
void make_sound() const { std::cout << "bark" << std::endl; }
};
class bird : public animal
{
public:
void make_sound() const { std::cout << "chirp" << std::endl; }
};
int main()
{
std::map<std::string, std::unique_ptr<animal>> m;
m.insert(std::make_pair("stupid_dog_name", new dog));
m.insert(std::make_pair("stupid_bird_name", new bird));
m["stupid_dog_name"]->make_sound();
return 0;
}
You may have template on classes and functions, but not on instances.
You should stick to the map to BaseClass*'es.
Below is the expansion of solution suggested by anton.
#include <iostream>
#include <string>
#include <map>
#include <utility>
using namespace std;
class BaseClass
{
string s;
public:
BaseClass() { s = "BaseClass";}
virtual ~ BaseClass(){}
virtual void print()=0;
};
class Derived1 : public BaseClass
{
int i;
public:
Derived1() { i = 10; }
void print()
{
cout << i << std::endl;
}
};
class Derived2 : public Derived1
{
float f;
public:
Derived2() { f = 4.3;}
void print()
{
cout << f << std::endl;
}
};
class factory
{
map<string, BaseClass*>m;
BaseClass* obj;
public:
factory()
{
obj=NULL;
}
BaseClass* FindType(string s);
void AddType(string s,BaseClass *obj);
void deleter();
~factory(){cout<<"deleting objects from map"<<endl;
deleter();
}
};
void factory :: AddType(string s,BaseClass* obj)
{
m.insert(make_pair(s,obj ));
}
void factory ::deleter ()
{
for (auto pObj = m.begin( );
pObj != m.end( ); ++pObj) {
delete pObj->second;
}
m.clear( );
}
BaseClass* factory::FindType(string s)
{
if(m.find(s)!=m.end())
{
return m[s];
}
return NULL;
}
int main()
{
BaseClass* obj;
factory fact_obj;
fact_obj.AddType("d1",new Derived1());
fact_obj.AddType("d2",new Derived2());
obj=fact_obj.FindType("d1");
if(obj!=NULL)
{
obj->print();
}
obj=fact_obj.FindType("d2");
if(obj!=NULL)
{
obj->print();
}
return 0;
}