I have an old factory implementation in c++, and I want to use unique pointers instead of raw pointers in it. A minimal example of my code is as follows. I have a base class A, and a derived class B. In main(), I pass 1 to the create method in A, and the type of b1 is now changed to B.
#include <iostream>
#include <map>
class A {
public:
A() {}
virtual void Foo() {}
std::map<int, A *> ®isterType() {
static std::map<int, A *> map_instance;
return map_instance;
}
A *create(int n) { return registerType()[n]; }
};
class B : A {
public:
B() { registerType()[1] = this; }
void Foo() { std::cout << "I am B!\n"; }
};
static B b0;
int main() {
A *b1 = new A();
b1 = b1->create(1);
b1->Foo();
return 0;
}
Now if I want to change raw pointers to unique pointers, I naturally get a collection of errors (the following code results in errors):
#include <iostream>
#include <map>
#include <memory>
class A {
public:
A() {}
virtual void Foo() {}
std::map<int, std::unique_ptr<A>> ®isterType() {
static std::map<int, std::unique_ptr<A>> map_instance;
return map_instance;
}
std::unique_ptr<A> create(int n) { return registerType()[n]; }
};
class B : A {
public:
B() { registerType()[1](this); }
void Foo() { std::cout << "I am B too!\n"; }
};
static B b0;
int main() {
std::unique_ptr<A> b1(new A());
b1 = b1->create(1);
b1->Foo();
return 0;
}
The errors are:
In member function 'std::unique_ptr<A> A::create(int)':
use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = A; _Dp = std::default_delete<A>]'
std::unique_ptr<A> create(int n) { return registerType()[n]; }
In constructor 'B::B()':
no match for call to '(std::map<int, std::unique_ptr<A> >::mapped_type {aka std::unique_ptr<A>}) (B* const)'
B() { registerType()[1](this); }
^
So I want to know:
Were unique pointers intended to be used in cases like mine? (I assume the response should be yes!)
I need to pass this as a unique_ptr type to the registerType method. How I can pass the ownership of the pointer to the current instance (this keyword) to a unique_ptr? (If it is possible or was intended to be possible.)
If it is a good practice to use unique pointers here, how I should implement it?
First of all, if someone wants to implement a factory pattern, an acceptable way of doing it with raw pointers is as follows:
#include <iostream>
#include <map>
class A;
class A_Factory {
public:
A_Factory() {}
virtual A *create() = 0;
};
class A {
public:
A() {}
static void registerType(int n, A_Factory *factory) {
get_factory_instance()[n] = factory;
}
static A *create(int n) {
A *A_instance = get_factory_instance()[n]->create();
return A_instance;
}
virtual void setMyID(int n) {}
virtual void I_am() { std::cout << "I am A\n"; }
virtual ~A() {}
protected:
int MyID;
static std::map<int, A_Factory *> &get_factory_instance() {
static std::map<int, A_Factory *> map_instance;
return map_instance;
}
};
class B : public A {
public:
B() {}
void Foo() {}
void I_am() { std::cout << "I am B " << MyID << "\n"; }
void setMyID(int n) { MyID = n; }
~B() {}
private:
};
class B_Factory : public A_Factory {
public:
B_Factory() { A::registerType(1, this); }
A *create() { return new B(); }
};
static B_Factory b0_factory;
void caller() {}
int main() {
A *b1 = A::create(1);
A *b2 = A::create(1);
b1->setMyID(10);
b2->setMyID(20);
b1->I_am();
b2->I_am();
delete b1;
delete b2;
return 0;
}
A is the base class, and B is the derived one. If we pass 1 to A::create(int n), an object of type B will be produced. The memory is managed manually and there would be no memory leak.
Concerning the questions in the post:
YES. unique_ptr is awesome; use them wherever you can!
With the design presented in the question, passing the ownership of this was somehow necessary. I cannot think of a way to pass the ownership of this. With the design presented in the answer, it is not necessary to pass the ownership of this.
Implement the unique_ptr in the above factory pattern as below:
#include <iostream>
#include <map>
#include <memory>
class A;
class A_Factory {
public:
A_Factory() {}
virtual std::unique_ptr<A> create_unique() = 0;
};
class A {
public:
A() {}
static void registerType(int n, A_Factory *factory) {
get_factory_instance()[n] = factory;
}
static std::unique_ptr<A> create_unique(int n) {
std::unique_ptr<A> A_instance =
std::move(get_factory_instance()[n]->create_unique());
return A_instance;
}
virtual void setMyID(int n) {}
virtual void I_am() { std::cout << "I am A\n"; }
virtual ~A() {}
protected:
int MyID;
static std::map<int, A_Factory *> &get_factory_instance() {
static std::map<int, A_Factory *> map_instance;
return map_instance;
}
};
class B : public A {
public:
B() {}
void Foo() {}
void I_am() { std::cout << "I am B " << MyID << "\n"; }
void setMyID(int n) { MyID = n; }
~B() {}
private:
};
class B_Factory : public A_Factory {
public:
B_Factory() { A::registerType(1, this); }
std::unique_ptr<A> create_unique() {
std::unique_ptr<A> ptr_to_B(new B);
return ptr_to_B;
}
};
static B_Factory b0_factory;
void caller() {}
int main() {
std::unique_ptr<A> b1 = std::move(A::create_unique(1));
std::unique_ptr<A> b2 = std::move(A::create_unique(1));
b1->setMyID(10);
b2->setMyID(20);
b1->I_am();
b2->I_am();
return 0;
}
As you can see, no manual memory management is necessary and the memory management is handled by the unique_ptr.
Related
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
}
This question already has answers here:
How to store object of different class types into one container in modern c++?
(2 answers)
Closed 3 years ago.
I have multiple classes with same function as below
class A
{
void display()
{
// display something
}
};
class B
{
void display()
{
// display something two
}
};
I want to store difference class at a list or a vector and loop to call the same function with same name
int main()
{
A * a;
B * b;
//list or vector to store object
std::vector < Something that can store different class > listofclass;
listofclass.emplace_back(a);
listofclass.emplace_back(b);
for (int i = 0; i < listofclass.size(); i++)
{
listofclass[i].display();
}
}
Is that possible to do like this?
Because there is separate classes, having different purpose, and now i try to group them together
Or there is other alternative way to achieve something like this
If you control the definition of A and B, you can write a common base class, and have them inherit it.
class can_display {
public:
virtual void display() = 0;
virtual ~can_display() = default;
};
class A : public can_display
{
void display() override
{
// display something
}
};
class B : public can_display
{
void display() override
{
// display something two
}
};
int main()
{
A a;
B b;
std::vector<can_display *> displayables;
displayables.push_back(&a);
displayables.push_back(&b);
for (can_display * displayable : displayables)
{
displayable->display();
}
}
As an alternative to changing the definition of A and B to inherit from a common base, you can have a wrapper that inherits.
template <typename T>
class can_display_impl {
T * wrapped;
public:
can_display_impl(T * wrapped) : wrapped(wrapped) {}
void display() override { wrapped->display(); }
}
template <typename T>
std::unique_ptr<can_display> make_can_display(T & wrapped) {
return std::make_unique<can_display_impl<T>>(&wrapped);
}
int main()
{
A a;
B b;
std::vector<std::unique_ptr<can_display>> displayables;
displayables.emplace_back(make_can_display(a));
displayables.emplace_back(make_can_display(b));
for (auto & displayable : displayables)
{
displayable->display();
}
}
You have two solutions for this problem:
Use inheritance and just make a abstract class that will be a interface for your classes. In class A and class B just inherit from that interface and in std::vector hold pointer to base class.
#include <vector>
#include <iostream>
#include <memory>
class Interface_display {
public:
virtual void display() = 0;
virtual ~Interface_display(){};
};
class A : public Interface_display
{
public:
void display() override
{
std::cout << "Display from A\n";
}
~A() override = default;
};
class B : public Interface_display
{
public:
void display() override
{
std::cout << "Display from B\n";
}
~B() override = default;
};
int main(void)
{
std::vector<std::unique_ptr<Interface_display>> v;
v.emplace_back(std::make_unique<A>());
v.emplace_back(std::make_unique<B>());
for (const auto &element: v) {
element->display();
}
}
And if you are using c++17, you could use std::variant and wrap objects of your class to std::variant:
#include <vector>
#include <iostream>
#include <variant>
class A
{
public:
void display()
{
std::cout << "Display from A\n";
}
};
class B
{
public:
void display()
{
std::cout << "Display from B\n";
}
};
int main(void)
{
using variant_t = std::variant<A, B>;
std::vector<variant_t> v;
v.emplace_back(A());
v.emplace_back(B());
for (auto &element: v) {
std::visit([](auto &x) { x.display(); }, element);
}
}
https://wandbox.org/permlink/8VBmziWzafbPZk99
A way to solve this problem is by using polymorphism. You make a superclass, which contains a pure virtual version of this function and let both A and B inherit from this class. By doing this, you can dynamic_cast any pointer of type A or B to a superclass type, on which you have defined the display function.
This will get you something like this
class C {
public:
virtual void display() = 0;
virtual ~C() = default;
};
class A : public C {
public:
void display() override {
std::cout << "A" << std::endl;
};
~A() override = default;
};
class B : public C {
public:
void display(){
std::cout << "B" << std::endl;
};
~B() override = default;
};
So you can do:
C* c = new A();
// You can put the types of C* in the same list, and iterate over this list and do on each element
c->display();
delete c;
I have two classes A,B which inherit from an abstract base class Abs. I would like to create an initialization list containing both of them. I would like to iterate on that list with a foreach loop.
class Abs {
public:
virtual ~Abs() = default;
virtual void f() = 0;
};
class A : public Abs {
virtual void f() override;
};
class B : public Abs {
virtual void f();
};
int main() {
A a;
B b;
const Abs& a_abs = a;
const Abs& b_abs = b;
for (const auto& abs : {a_abs, b_abs})
{
}
return 0;
}
The compilation of the for loop fails with:
error: cannot allocate an object of abstract type ‘Abs’
Why is it trying to allocate an Abs type?
How can I overcome that?
Thank you :)
there were a few things wrong with your code:
you should have a public destructor/constructor
B doesn't inherit from Abs therefore in can't be converted to Abs
i don't know if you can get what you want with references but with pointers you can. please use smart pointer this is just a prof of concept
#include <initializer_list>
#include <iostream>
class Abs {
public:
virtual ~Abs() = default;
virtual void f() const = 0;
};
class A : public Abs {
public:
virtual void f() const {
std::cout << "A" << std::endl;
}
};
class B : public Abs {
public:
virtual void f() const {
std::cout << "B" << std::endl;
}
};
int main() {
A* a = new A();
B* b = new B();
const Abs* a_abs = dynamic_cast<const Abs *>(a);
const Abs* b_abs = dynamic_cast<const Abs *>(b);
for (const auto* abs : {a_abs, b_abs})
{
abs->f();
}
delete a;
delete b;
return 0;
}
I have a class derived from an interface and a friend class of the derived class. I want to access the members of derived class which is instantiated as interface. It looks like this:
Interface:
class AInterface
{
public:
virtual ~AInterface() = default;
virtual void set(int a) = 0;
};
Derived class A with friend class B:
class B;
class A : public AInterface
{
public:
~A() override {}
void set(int a) override
{
mem = a;
}
private:
friend class B;
int mem = 0;
};
class B:
class B
{
public:
B()
{
a = new A();
a->set(3);
}
int get_a()
{
// Access mem since it's a friend class
return a->mem;
}
private:
AInterface *a;
}
main:
int main()
{
B *b = new B();
std::cout << b->get_a() << std::endl;
return 0;
}
The program does not compile saying AInterface has no member named 'mem'.
Do I need getter functions in the interface and implement it in A to achieve this or is there any other way to do it?
Now work
#include <iostream>
using namespace std;
class AInterface
{
public:
virtual ~AInterface() = default;
int getMem() { return mem; }
virtual void set(int a) = 0;
protected:
int mem = 0;
};
class A : public AInterface
{
public:
~A() override {}
void set(int a) override
{
mem = a;
}
};
class B
{
public:
B()
{
a = new A{};
a->set(3);
}
int get_a()
{
// Access mem since it's a friend class
return a->getMem();
}
private:
AInterface *a;
};
int main()
{
B *b = new B();
std::cout << b->get_a() << std::endl;
return 0;
}
Method which is override by child and is pure, should be virtual.
If each class (child) Interface, variable int mem should be protected in interface.
Now works fine, like you want.
Add getter getMem()
Version with friend
#include <iostream>
using namespace std;
class AInterface
{
public:
virtual ~AInterface() = default;
virtual void set(int a) = 0;
protected:
friend class B;
int mem = 0;
};
class A : public AInterface
{
public:
~A() override {}
void set(int a) override
{
mem = a;
}
};
class B
{
public:
B()
{
a = new A{};
a->set(3);
}
int get_a()
{
// Access mem since it's a friend class
return a->mem;
}
private:
AInterface *a;
};
int main()
{
B *b = new B();
std::cout << b->get_a() << std::endl;
return 0;
}
In your class B.
class B
{
//...
int get_a()
{
return a->mem; // but a is a AInterface* !!!
}
private:
AInterface *a; // That's not an A*, but an AInterface*
};
You have 2 options.
use dynamic_cast<>
int B::get_a()
{
A* p = dynamic_cast<A*>(a);
if (p)
return p->mem;
// a is not an A*, it's another AInterface*-type object !!!
// What should you do?
throw something_or_other(); // throw?
return -1; // return an error code?
}
// or maybe add.. so you can check for errors before calling get_a()
A* B::get_A_ptr() const
{
return dynamic_cast<A*>(a);
}
dynamic_cast works fine, but can slow down your app if you need to make frequent reads of a->mem.
Store a in an A*, which is probably what you meant to do from the start...
class B
{
// ...
private:
A* a; // now a->A::mem is visible.
};
Since you explicitly call new A in B's constructor, I think option 2 is better for your case.
This might be a case for the switch-off rule explained in C++ coding standards and I am wondering if I am doing it correctly. I am wondering because I still have if-clauses in the switching function.
Class A never gets instantiated directly, it's always either B or C that get dynamically created and uniformly handled through a (shared) pointer to A. foo switches and selects the operation depending on whether it's an B or C.
class A {
public:
virtual ~A(){}
};
class B : public A {};
class C : public A {};
typedef std::shared_ptr<A> Aptr;
typedef std::shared_ptr<B> Bptr;
typedef std::shared_ptr<C> Cptr;
template<class T>
std::shared_ptr<T> get(const Aptr& pA) {
return std::dynamic_pointer_cast< T >( pA );
}
void foo( const Bptr& pB ) {
std::cout << "operate on B\n";
}
void foo( const Cptr& pC ) {
std::cout << "operate on C\n";
}
void foo( const Aptr& pA ) {
if ( auto x = get<B>(pA) ) {
foo(x);
return;
}
if ( auto x = get<C>(pA) ) {
foo(x);
return;
}
assert(!"oops");
}
int main()
{
Aptr pA( new C );
foo( pA );
}
My question is whether void foo( const Aptr& pA ) can be implemented more elegantly. That could mean without if. Is throwing in get and catching in foo recommended in this situation?
Unless you have good reasons for doing otherwise (and if you have them, your code does not show them), this seems to me like the typical use case for dynamic polymorphism achieved through a virtual function:
class A
{
public:
virtual ~A() {}
virtual void foo() = 0;
};
class B : public A
{
virtual void foo()
{
std::cout << "operate on B\n";
}
};
class C : public A
{
virtual void foo()
{
std::cout << "operate on B\n";
}
};
Besides, in C++11 it is preferable to use std::make_shared<>() over the construction of a shared_ptr with a naked new allocation (again, unless you have good reasons to do otherwise):
int main()
{
Aptr pA = std::make_shared<C>();
pA->foo();
}
If you have reasons not to use virtual functions and prefer a different, non-intrusive kind of polymorphism, you may use Boost.Variant in combination with boost::static_visitor. This does not even require B and C to be related.
#include <boost/variant.hpp>
#include <memory>
#include <iostream>
class B /* ... */ {};
class C /* ... */ {};
// ...
typedef std::shared_ptr<B> Bptr;
typedef std::shared_ptr<C> Cptr;
struct foo_visitor : boost::static_visitor<void>
{
void operator () (Bptr p)
{
std::cout << "operate on B\n";
}
void operator () (Cptr p)
{
std::cout << "operate on C\n";
}
};
int main()
{
boost::variant<Bptr, Cptr> ptr;
ptr = std::make_shared<C>();
foo_visitor v;
ptr.apply_visitor(v);
}
This approach is pretty similar to the one you chose, except that Boost.Variant also makes sure you are not forgetting to include a handling case for each of the values the variant could possibly assume (in this case, Bptr and Cptr).
Just use virtual member functions. There's no substitute for the real thing
class A {
public:
virtual ~A(){}
virtual void foo() = 0;
};
class B : public A {
public:
virtual void foo() {
std::cout << "operate on B\n";
}
};
class C : public A {
public:
virtual void foo() {
std::cout << "operate on C\n";
}
};
and pick a good C++ introductory book.