I have some code like:
class Base {
virtual bool acceptsData(char*) = 0;
};
class Derived1 : public Base {
virtual bool acceptsData(char*) { /* do something */ }
};
class Derived2 : public Base {
virtual bool acceptsData(char*) { /* do something else */}
}
Base* createStuff(char* data)
{
Base* d1 = new Derived1();
if(d1->acceptsData(data))
{
return d1;
}
delete d1;
Base* d2 = new Derived2();
if(d2->acceptsData(data))
{
return d2;
}
delete d2;
// and more ...
}
// .... somewhere later
int main()
{
Base* Aclass = createStuff("abc");
}
I'd like to get rid of this long if() ... construct, and use some more generalized patterns, but I still did not manager to come up with something useful. Is there a better way of doing this?
If you want to factorize code as you have several Derived classes, you may use something like the following:
namespace detail
{
template <typename T> std::unique_ptr<Base> make_base(const char* data)
{
std::unique_ptr<Base> base = std::make_unique<T>();
if (base->acceptsData(data)) {
return base;
}
return nullptr;
}
template <typename... Ts> std::unique_ptr<Base> createStuff(const char* data)
{
std::function<std::unique_ptr<Base>(const char*)> fs[] = { make_base<Ts>... };
for(auto& f : fs) {
auto base = f(data);
if(base) {
return base;
}
}
return nullptr;
}
}
Base* createStuff(const char* data) {
return detail::createStuff<Derived1, Derived2/* and other Derived classes*/>(data).release();
}
Live example.
You are creating your objects. Factory or Builder are suitable patterns for you.
What might meet your requirements is something the virtual constructors design pattern. This is what it looks like...
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Base {
Base* b;
// suppress the usual constructors
Base(Base&);
Base operator=(Base&);
protected:
Base() { b = 0; };
public:
virtual void Print() { b->Print(); }
virtual ~Base() {
if (b) {
delete b;
}
}
Base(string type);
};
class Derived1 : public Base {
Derived1(Derived1&);
Derived1 operator=(Derived1&);
Derived1() {}
friend class Base;
public:
void Print() { cout << "Derived1::Print()" << endl; }
~Derived1() { }
};
class Derived2 : public Base {
Derived2(Derived2&);
Derived2 operator=(Derived2&);
Derived2() {}
friend class Base;
public:
void Print() { cout << "Derived2::Print()" << endl; }
~Derived2() { }
};
Base::Base(string type) {
if (type == "Derived1")
b = new Derived1;
else if (type == "Derived2")
b = new Derived2;
}
int main() {
vector<Base*> bases;
cout << "virtual constructor calls:" << endl;
bases.push_back(new Base("Derived2"));
bases.push_back(new Base("Derived1"));
bases.push_back(new Base("Derived1"));
bases.push_back(new Base("Derived2"));
for (int i = 0; i < bases.size(); i++) {
bases[i]->Print();
}
cout << "destructor calls:" << endl;
for (int j = 0; j < bases.size(); j++) {
delete bases[j];
}
// system("pause");
return 0;
}
Related
In the virtual method create() in the derived class Derived, I return a struct of type HelpDerived. However, since I had to set the return type of the method to HelpBase, I found that I need to cast the returned object back to the type HelpDerived.
The following is an example of my case.
#include <iostream>
struct HelpBase {
int a = 0;
virtual void output() {}
};
struct HelpDerived : HelpBase {
int b = 0;
void output() override {}
};
class Base {
public:
virtual HelpBase create() = 0;
};
class Derived : public Base {
public:
HelpBase create() override;
};
HelpBase Derived::create() {
HelpDerived d;
d.a = 1;
d.b = 2;
return d;
}
int main() {
Derived d;
auto based = d.create();
HelpDerived derived = dynamic_cast<HelpDerived &>(based);
std::cout << derived.a << std::endl;
}
When I run the code abve, I get the error
terminate called after throwing an instance of 'std::bad_cast'
what(): std::bad_cast
Abort trap: 6
What have I misunderstood about objects and casting in C++? Why does this method not work?
What can I do to fix the problem?
I think you'd better return a pointer to avoid object slicing in your create function.
#include <iostream>
struct HelpBase {
int a = 0;
virtual void output() {}
};
struct HelpDerived : HelpBase {
int b = 0;
void output() override {}
};
class Base {
public:
virtual HelpBase* create() = 0;
};
class Derived : public Base {
public:
HelpBase* create() override;
};
HelpBase* Derived::create() {
HelpDerived* d = new HelpDerived;
d->a = 1;
d->b = 2;
return d;
}
int main() {
Derived d;
auto based = d.create();
HelpDerived* derived = dynamic_cast<HelpDerived *>(based);
std::cout << derived->a << " " << derived->b << std::endl;
delete derived;
}
I've replaced dynamic cast by static cast and it worked for me almost fine.
#include <iostream>
struct HelpBase {
int a = 0;
virtual void output() {}
};
struct HelpDerived : HelpBase {
int b = 0;
void output() override {}
};
class Base {
public:
virtual HelpBase create() = 0;
};
class Derived : public Base {
public:
HelpBase create() override;
};
HelpBase Derived::create() {
HelpDerived d;
d.a = 3;
d.b = 2;
return d;
}
int main() {
Derived d;
auto based = d.create();
HelpDerived derived = static_cast<HelpDerived &>(based);
std::cout << derived.a << std::endl;
std::cout << derived.b << std::endl;
}
Output:
3
32726
Note that a value is correct, while b is junk. This is because for derived constructor has not been called.
In general, casting from base class to derived is not recommended, as derived may have more data members, than base class.
Recommended reading: https://www.bogotobogo.com/cplusplus/upcasting_downcasting.php
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
}
#include <iostream>
using namespace std;
class Base
{
public:
void who()
{
cout << "I am " << _name << endl;
}
protected:
std::string _name;
};
class A : public Base
{
public:
A()
{
_name = "A class";
}
};
class B : public Base
{
public:
B()
{
_name = "B class";
}
};
class Wrapper
{
public:
Wrapper(Base *i):_data(i)
{
}
operator A()
{
A a;
// dynamic_cast<A*>(_data);
return a;
}
operator B()
{
B a;
// dynamic_cast<B*>(_data);
return a;
}
private:
Base* _data;
};
void madeForClass(A iObject)
{
cout << "call madeForClass A";
}
void madeForClass(B iObject)
{
cout << "call madeForClass B";
}
int main()
{
A a;
Base* b = &a;
madeForClass(Wrapper(b));
return 0;
}
when I execute this, I get error from compile saying:
error: call of overloaded 'madeForClass(Wrapper)' is ambiguous
I understand that it cannot deduce right function even though i have overloaded the typecast. But, How can I achieve such dynamism?
For more info, I somehow want to use the dynamic_cast in the overloading function or somewhere in such a way that based on the outcome of cast it should choose the corresponding madeForClass function.
For the given example, the cast will fail for 'B' hence should call madeForClass(A i);
As alternative, you may do
class Wrapper
{
public:
Wrapper(Base *i) : _data(i) {}
template <typename F>
auto Apply(F f)
{
if (auto a = dynamic_cast<A*>(_data)) {
f(*a);
} else if (auto b = dynamic_cast<B*>(_data)){
f(*b);
}
}
private:
Base* _data;
};
And then
Wrapper(base).Apply([](const auto& e){ madeForClass(e); });
Demo
or use Visitor instead of manual dynamic_cast
I have a need to clone a derived class given only a reference or pointer to the base class. The following code does the job, but doesn't seem elegant, because I'm putting boilerplate code into many derived classes C, D, E that are siblings of B (not shown) that just calls the default copy constructor of each. Isn't that what the default copy constructor is for, if only it could be virtual?
Is there a better way?
Making a virtual assignment operator would be wrong, as I don't want C to assign to B, B to D, etc, just clone B, C, D or E.
#include <iostream>
using namespace std;
class A {
public:
virtual ~A() {}
virtual A* clone()=0;
};
class B : public A {
int i;
public:
virtual A* clone() {
cout << "cloned B" << endl;
return new B(*this);
}
virtual ~B() { cout << "destroyed b" << endl; }
};
int main() {
A* a = new B();
A* aa = a->clone();
delete a;
delete aa;
return 0;
}
You could always stick all the cloning logic into its own class in the middle of the hierarchy:
template <class Derived, class Base>
class CloneCRTP : public Base {
public:
Derived* clone() const override {
return new Derived(static_cast<Derived const&>(*this));
}
};
And then:
class B : public CloneCRTP<B, A>
{
int i;
public:
virtual ~B() { cout << "destroyed b" << endl; }
};
No more boilerplate.
You can rely on the CRTP idiom.
It follows a minimal, working example:
struct B {
~virtual ~B() { }
virtual B* clone() = 0;
};
template<class C>
struct D: public B {
B* clone() {
return new C{*static_cast<C*>(this)};
}
};
struct S: public D<S> { };
int main() {
B *b1 = new S;
B *b2 = b1->clone();
delete b1;
delete b2;
}
To achieve clone that works as with covariant return type, there is a need for some more complicated CRTP:
class Shape {
// virtual
virtual Shape* do_clone() const = 0;
public:
virtual ~Shape() {}
// non-virtual
Shape* clone() const {
return do_clone();
}
// ...
};
template <class Derived, class Base>
class CloneCRTP : public Base {
// virtual
Base* do_clone() const override {
return new Derived(static_cast<Derived const&>(*this));
}
public:
// non-virtual
Derived* clone() const {
return static_cast<Derived*>(do_clone());
}
};
Usage:
class Rectangle: public CloneCRTP<Rectangle, Shape> { /*...*/ };
class Triangle: public CloneCRTP<Triangle, Shape> { /*...*/ };
int main() {
Rectangle* r1 = new Rectangle{};
// getting the proper type from clone:
Rectangle* rcopy = r1->clone();
delete rcopy;
delete r1;
Triangle t1{};
// getting the proper type from clone:
Triangle* tcopy = t1.clone();
delete tcopy;
}
Code: http://coliru.stacked-crooked.com/a/339458f8b45299c3
I do it in a generalized way.
Definition:
template <class Class>
class CloneInterface {
public:
Class* copy() const { return new Class{static_cast<Class const&>(*this)}; }
virtual Class* clone() const { return this->copy(); }
};
template <class Derived, class Base>
class CloneCRTP : public Base {
public:
Derived* copy() const { return new Derived{static_cast<Derived const&>(*this)}; }
Base* clone() const override { return this->copy(); }
};
Usage:
class Base : public CloneInterface<Base> {
private:
int a = 0;
public:
virtual ~Base() {}
void print() { std::cout << "Base: a = " << a << '\n'; }
};
class A : public CloneCRTP<A, Base> {
private:
int b = 1;
public:
void print() { std::cout << "A: b = " << b << '\n'; }
};
Example:
int main() {
auto b = new Base();
auto b_clone = b->clone();
auto b_copy = b->copy();
b->print(); // Base print()
b_clone->print(); // Base print()
b_copy->print(); // Base print()
std::cout << "=========================\n";
auto a = new A();
auto a_clone = a->clone(); // returns Base*
auto a_copy = a->copy(); // returns A*
a->print(); // A print()
a_clone->print(); // Base print(), because clone returns pointer to the base class
a_copy->print(); // A print()
std::cout << "=========================\n";
auto c = static_cast<Base*>(a);
auto c_clone = c->clone(); // returns Base*, but A* inside
auto c_copy = c->copy(); // returns Base*, that is really Base
c->print(); // Base print()
c_clone->print(); // Base print()
c_copy->print(); // Base print()
std::cout << "=========================\n";
auto a_clone_restored = static_cast<A*>(c_clone);
auto a_copy_restored = static_cast<A*>(c_copy); // Invalid
a_clone_restored->print(); // A print()
a_copy_restored->print(); // A print()
delete b;
delete b_clone;
delete b_copy;
delete a;
delete a_clone;
delete a_copy;
return 0;
}
This approach allows to reuse crtp definition in all hierarchies that require clone functionality.
Code: https://coliru.stacked-crooked.com/a/269a2427fd2f919b
I have a problem with inheritance in C++. The attached code produces the output "1,1," but I thought the action methods from the classes b and c replace the action method from class a. So I expected the output "2,3,". What do I have to change to get the output "2,3,"?
#include <iostream>
//Class a
class a
{
public:
a();
int action();
};
a::a()
{
}
int a::action()
{
return 1;
}
//Class b
class b : public a
{
public:
b();
int action();
};
b::b()
{
}
int b::action()
{
return 2;
}
//Class c
class c : public a
{
public:
c();
int action();
};
c::c()
{
}
int c::action()
{
return 3;
}
//Main Programm
int main()
{
a arr[2];
arr[0] = b();
arr[1] = c();
for(int i = 0; i<2; i++)
{
std::cout << arr[0].action() << ",";
}
return 0;
}
Action needs to be virtual in the base class, otherwise you can't override it.
You can use the foo() override notation to get a compile-time check as to whether you're really overriding something.
You will have to access the derived type trough a pointer to the base type, otherwise you'll slice and do other nasty things. Also sometimes it's a good idea to also make your destructor virtual.
class Base { };
class Derived : public Base { };
some_container<Base*> baseOrDerived;
Then you can allocate both Base and Derived objects into this container. For example with new, although you probably want to use std::shared_ptr<Base> or std::unique_ptr<Base> instead of Base*.
you can use virtual function to get the output "2,3":
first, you should change void action(); to virtual void action(); in class a;
second, you should use pointer to implement polymorphism;
third, you should change arr[0] to arr[i];
Here is my code:
#include <iostream>
//Class a
class a
{
public:
a();
virtual int action();
};
a::a()
{
}
int a::action()
{
return 1;
}
//Class b
class b : public a
{
public:
b();
int action();
};
b::b()
{
}
int b::action()
{
return 2;
}
//Class c
class c : public a
{
public:
c();
int action();
};
c::c()
{
}
int c::action()
{
return 3;
}
int main(int argc, char *argv[])
{
a *(arr[2]);
arr[0] = new b();
arr[1] = new c();
for(int i = 0; i<2; i++)
{
std::cout << arr[i]->action() << ",";
}
return 0;
}
Here is my output: