How to get access to the derived std::shared_ptr? - c++

Suppose I have code like that one, and I want to get access to the myClassB members. How can I do that? I need to use the functionality of functionA.
I can't change it because it is from the 3rd party library. And I need to use functionA to create it, and get values created by it. In this case "Test_1" string
class myClassA {
public:
myClassA(){}
~myClassA(){}
};
class myClassB : public myClassA
{
public:
myClassB(){}
void setString1(std::string newString)
std::string getS1()
private:
std::string privateMember;
};
std::shared_ptr<myClassA> functionA()
{
std::shared_ptr<myClassB> temporary(new myClassB());
temporary->setString1("TEST_1");
return std::move(temporary);
}
int main()
{
std::shared_ptr<myClassA> myPtr; // = functionA(); ??
}

Theoretically, you could use a dynamic_cast (or in this case specifically, std::dynamic_pointer_cast to get the derived pointer type. Like so:
std::shared_ptr<MyClassA> a_ptr = functionA();
std::shared_ptr<MyClassB> b_ptr = std::dynamic_pointer_cast<MyClassB>(a_ptr);
if(b_ptr) {//Check to verify the cast was successful
b_ptr->setString("Test1");
}
There is, however, a major caveat to this. In order for dynamic_cast (and therefore std::dynamic_pointer_cast) to work, your object hierarchy must have a virtual table defined. That means at least one of the methods defined by MyClassA must be declared virtual. The simplest solution is to declare the destructor virtual, since that's good practice whenever you're defining polymorphic objects (since you need it to ensure that any derived classes clean up their resources correctly).
class MyClassA {
public:
MyClassA() = default;
virtual ~MyClassA() = default;
};

Agree with dynamic_cast but without a virtual function table in ClassA, something like this would have to do:
Test This Code
#include <string>
#include <memory>
#include <iostream>
#include <set>
class myClassA {
public:
myClassA(){}
~myClassA(){}
};
class myClassB;
class ClassB_Registry{
private:
ClassB_Registry(){
}
~ClassB_Registry(){
}
public:
static ClassB_Registry* Get(){ static ClassB_Registry obj; return &obj; }
static void Register(myClassB* ptr){
Get()->mPointers.insert(ptr);
}
static void UnRegister(myClassB* ptr){
Get()->mPointers.erase(ptr);
}
static myClassB* Cast(myClassA* ptr){
if(Get()->mPointers.count((myClassB*)ptr) > 0) return (myClassB*)ptr;
return nullptr;
}
private:
std::set<myClassB*> mPointers;
};
class myClassB : public myClassA
{
public:
myClassB(){ ClassB_Registry::Register(this); }
~myClassB(){ ClassB_Registry::UnRegister(this); }
void setString1(std::string newString){privateMember = newString;}
std::string getS1() { return privateMember; }
private:
std::string privateMember;
};
std::shared_ptr<myClassA> functionA()
{
std::shared_ptr<myClassB> temporary(new myClassB());
temporary->setString1("TEST_1");
return std::move(temporary);
}
int main()
{
std::shared_ptr<myClassA> myPtr = functionA(); //??
std::shared_ptr<myClassA> myPtr_a(new myClassA()); //??
myClassB* pDerrived = ClassB_Registry::Cast(myPtr.get()); // bridge the RTTI gap
if(pDerrived)
std::cout << pDerrived->getS1();
pDerrived = ClassB_Registry::Cast(myPtr_a.get()); // works on A pointers to return null
if(pDerrived)
std::cout << pDerrived->getS1() << " \n";
else
std::cout << "Not A Pointer of Type B" << " \n";
}
It's not pretty, but if myClassB had a virtual table as mentioned previously, and all future derived classes used myClassB as the base, then you could bridge the gap for RTTI.

Related

How to deal with different classes which have the same method?

For example, I have 2 classes (in reality, it's more, that's why I'm asking this question) with the same methods:
class class1{
public:
void init(){
//something
}
void dostuff(){
//something
}
//
};
class class2{
public:
void init(){
//something
}
void dostuff(){
//something
}
//
};
And now a third one in which I want to deal with the two classes in the same manner:
class upclass{
public:
upclass(class12* argclass){
myclass=argclass;
myclass->init();
}
void domorestuff(){
myclass->dostuff();
}
private:
class12* myclass; //pointer to class 1 OR class 2
};
My question is now, do I need multiple constructors and multiple declarations to make it work or is there a way around it? Is it even possible to make "class12" a spacekeeper for these types without preprocessor-directives?
I am sorry to say, this is a wide field and there are really many many possible solution.
But I guess that we are talking about object- oriented programming, derivation and plymorphic functions. What you describe, will be typically solved with a class hierachy.
You have one base class with virtual (polymorphic) functions.
Then you derive other classes from this base class and override the virtual functions from the base class.
In a 3rd step, you create some instances of the derived classes dynamically, during runtime and you store the newly created classes (their address) in a pointer to the base class.
Later, you can call any of the virtual overriden function through the base class pointer. And mechanism behind the scenes will call the correct function for you.
Additionally. You defined some function init. Such a function name suggests the usage of a class-constructor. This will be called automatically in the correct sequence. First the base class constructor and then the derived class constructor.
Please see the below example:
#include <iostream>
#include <string>
class Base {
std::string baseName{};
public:
Base() { // Do initialization stuff
baseName = "Base";
std::cout << "\nConstructor Base\n";
}
virtual void doStuff() { // virtual function
std::cout << baseName << '\n';
}
};
class Derived1 : public Base {
std::string derivedName{};
public:
Derived1() : Base() { // Do initialization stuff
derivedName = "Derived1";
std::cout << "Constructor Derived1\n";
}
void doStuff() override { // Override virtaul function
std::cout << derivedName << '\n';
}
};
class Derived2 : public Base {
std::string derivedName{};
public:
Derived2() : Base() { // Do initialization stuff
derivedName = "Derived2";
std::cout << "Constructor Derived2\n\n";
}
void doStuff() override { // Override virtaul function
std::cout << derivedName << '\n';
}
};
int main() {
Base* base = new Base();
Base* derived1 = new Derived1(); // Store in base class pointer
Base* derived2 = new Derived2(); // Store in base class pointer
base->doStuff();
derived1->doStuff(); // Magic of polymorphism
derived2->doStuff(); // Magic of polymorphism
}
The Base class pointer will accept all classes derived from Base.
Please note. In reality you ould not use raw pointers and also to the constructor differently. This is just fotr demo.
But, you need to read several books about it to get the complete understanding.
You can explicitly write "store one of these" via std::variant and obtain the actual type (when needed) through std::visit:
#include <variant>
using class12 = std::variant<class1*, class2*>;
class upclass {
public:
upclass(class12 argclass): myclass{argclass} {
visit([](auto classn) { classn->init(); }, myclass);
}
void domorestuff() {
visit([](auto classn) { classn->dostuff(); }, myclass);
}
private:
class12 myclass;
};
If those visits get too repetitive, you might consider writing a pretty API to hide them:
class prettyclass12: public std::variant<class1*, class2*> {
private: // both g++ and clang want variant_size<>, a quick hack:
auto& upcast() { return static_cast<std::variant<class1*, class2*>&>(*this); }
public:
using std::variant<class1*, class2*>::variant;
void init() { visit([](auto classn) { classn->init(); }, upcast()); }
void dostuff() { visit([](auto classn) { classn->dostuff(); }, upcast()); }
};
class prettyupclass {
public:
prettyupclass(prettyclass12 argclass): myclass{argclass} { myclass.init(); }
void domorestuff() { myclass.dostuff(); }
private:
prettyclass12 myclass;
};

Handling unique methods of Subclasses

I have a component in a software that can be described by an interface / virtual class.
Which non-virtual subclass is needed is decided by a GUI selection at runtime.
Those subclasses have unique methods, for which is makes no sense to give them a shared interface (e.g. collection of different data types and hardware access).
A minimal code example looks like this:
#include <iostream>
#include <memory>
using namespace std;
// interface base class
class Base
{
public:
virtual void shared()=0;
};
// some subclasses with shared and unique methods
class A : public Base
{
public:
void shared()
{
cout << "do A stuff\n";
}
void methodUniqueToA()
{
cout << "stuff unique to A\n";
}
};
class B : public Base
{
public:
void shared()
{
cout << "do B stuff\n";
}
void methodUniqueToB()
{
cout << "stuff unique to B\n";
}
};
// main
int main()
{
// it is not known at compile time, which subtype will be needed. Therefore: pointer has base class type:
shared_ptr<Base> basePtr;
// choose which object subtype is needed by GUI - in this case e.g. now A is required. Could also have been B!
basePtr = make_shared<A>();
// do some stuff which needs interface functionality... so far so good
basePtr->shared();
// now I want to do methodUniqueToA() only if basePtr contains type A object
// this won't compile obviously:
basePtr->methodUniqueToA(); // COMPILE ERROR
// I could check the type using dynamic_pointer_cast, however this ist not very elegant!
if(dynamic_pointer_cast<A>(basePtr))
{
dynamic_pointer_cast<A>(basePtr)->methodUniqueToA();
}
else
if(dynamic_pointer_cast<B>(basePtr))
{
dynamic_pointer_cast<B>(basePtr)->methodUniqueToB();
}
else
{
// throw some exception
}
return 0;
}
Methods methodUniqueTo*() could have different argument lists and return data which is omitted here for clarity.
I suspect that this problem isn't a rare case. E.g. for accessing different hardware by the different subclasses while also needing the polymorphic functionality of their container.
How does one generally do this?
For the sake of completeness: the output (with compiler error fixed):
do A stuff
stuff unique to A
You can have an enum which will represent the derived class. For example this:
#include <iostream>
#include <memory>
using namespace std;
enum class DerivedType
{
NONE = 0,
AType,
BType
};
class Base
{
public:
Base()
{
mType = DerivedType::NONE;
}
virtual ~Base() = default; //You should have a virtual destructor :)
virtual void shared() = 0;
DerivedType GetType() const { return mType; };
protected:
DerivedType mType;
};
// some subclasses with shared and unique methods
class A : public Base
{
public:
A()
{
mType = DerivedType::AType;
}
void shared()
{
cout << "do A stuff\n";
}
void methodUniqueToA()
{
cout << "stuff unique to A\n";
}
};
class B : public Base
{
public:
B()
{
mType = DerivedType::BType;
}
void shared()
{
cout << "do B stuff\n";
}
void methodUniqueToB()
{
cout << "stuff unique to B\n";
}
};
// main
int main()
{
shared_ptr<Base> basePtr;
basePtr = make_shared<B>();
basePtr->shared();
// Here :)
if(basePtr->GetType() == DerivedType::AType)
static_cast<A*>(basePtr.get())->methodUniqueToA();
else if(basePtr->GetType() == DerivedType::BType)
static_cast<B*>(basePtr.get())->methodUniqueToB();
return 0;
}
You can store an enum and initialize it at the constructor. Then have a Getter for that, which will give you the Type. Then a simple static cast after getting the type would do your job!
The goal of using polymorphism for the client is to control different objects with a single way. In other words, the client do not have to pay any attention to the difference of each object. That way, checking the type of each object violates the basic goal.
To achieve the goal, you will have to :
write the concrete method(methodUniqueToX()).
write a wrapper of the concrete method.
name the wrapper method abstract.
make the method public and interface/abstract.
class Base
{
public:
virtual void shared()=0;
virtual void onEvent1()=0;
virtual void onEvent2()=0;
};
// some subclasses with shared and unique methods
class A : public Base
{
private:
void methodUniqueToA()
{
cout << "stuff unique to A\n";
}
public:
void shared()
{
cout << "do A stuff\n";
}
void onEvent1()
{
this.methodUniqueToA()
}
void onEvent2()
{
}
};
class B : public Base
{
private:
void methodUniqueToB()
{
cout << "stuff unique to B\n";
}
public:
void shared()
{
cout << "do B stuff\n";
}
void onEvent1()
{
}
void onEvent2()
{
methodUniqueToB()
}
};

Instantiating a class with virtual methods without a heap allocation

class Base
{
public:
virtual ~Base() {}
virtual void Foo() = 0;
};
class FirstDerived: public Base
{
public:
void Foo() { cout << "FirstDerived" << endl; }
};
class SecondDerived: public Base
{
public:
void Foo() { cout << "SecondDerived" << endl; }
};
union PreallocatedStorage
{
PreallocatedStorage() {}
~PreallocatedStorage() {}
FirstDerived First;
SecondDerived Second;
};
class ContainingObject
{
public:
Base* GetObject()
{
if (!m_ptr)
{
// TODO: Make runtime decision on which implementation to instantiate.
m_ptr = new(&m_storage) SecondDerived();
}
return m_ptr;
}
~ContainingObject()
{
if (m_ptr)
{
m_ptr->~Base();
}
}
private:
PreallocatedStorage m_storage;
Base* m_ptr = nullptr;
};
int main()
{
auto object = make_unique<ContainingObject>();
// ...
// Later, at a point where I don't want to make more heap allocations...
// ...
auto baseObject = object->GetObject();
baseObject->Foo();
return 0;
}
What I'm trying to achieve here:
I need to instantiate a class that has virtual methods.
At the point in time I know exactly which derived class to instantiate, I cannot make further heap allocations (this is just out of curiosity, so the exact reason why is not relevant).
Hence, I want to somehow pre-allocate enough space to hold any possible implementation, and then decide later what class I'm going to instantiate in it.
Is there anything standards-non-compliant/undefined behavior in the above code?
The code is correct. See the comments on the question for some interesting insights, particularly the use of std::aligned_union which can be used as a generic replacement for the PreallocatedStorage union above.

Arrays of Pointers to Abstract Types

I have been experimenting with abstract types.
The code below gives me a desired effect.
class base{
public:
virtual void do_stuff() = 0;
};
class derived: public base{
public:
void do_stuff(){/*stuff*/}
};
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(base* ptr){
ptrs.emplace_back(ptr);
}
};
manager foo;
foo.add(new derived());
Fine and dandy, but it's awkward because the user is not only dealing with pointers, but has to use new without ever calling delete. My question is if there's a way I can implement this where the user of manager doesn't ever have to deal with pointers or new.
foo.add(derived()); //example
My attempts to implement this end up as:
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(base& ref){
ptrs.emplace_back(&ref);
}
};
But, the compiler says no known conversion from 'derived' to 'base&'. I have no idea how to make a reference to base compatible with a reference to derived. How do I get around this?
Pass unique_ptr
Your add function takes ownership of this object. A safe way of passing ownership is to pass unique_ptr.
Using a unique_ptr is fairly flexible because you can construct a shared_ptr from a unique_ptr or if you change your mind in the future you can store the unique_ptr directly.
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(std::unique_ptr<base> ptr){
ptrs.emplace_back(std::move(ptr));
}
};
manager foo;
foo.add(std::make_unique<derived>());
Using a temporary std::unique_ptr you avoid the owning raw pointer that is not exception safe. By using make_unique you can avoid writing new.
Live demo.
Pass a Factory
Another option if the caller really doesn't want to have to deal with any kind of pointer is to pass some sort of Factory that the add function uses to construct the object. The Factory could simply be a static create function on the derived class itself:
using Factory = std::function<std::unique_ptr<base>()>;
class manager{
std::vector<std::shared_ptr<base>> ptrs;
public:
void addUsing(const Factory& factory){
ptrs.emplace_back(factory());
}
};
class derived : public base {
public:
...
static std::unique_ptr<derived> create() {
return std::make_unique<derived>();
}
};
manager foo;
foo.addUsing(derived::create);
Live demo.
You can let your add() function be passed the arguments to be used in the construction of type T, where T is specified as the type of a subclass.
template <typename T, typename... TArgs>
void add(TArgs&&... args)
{
ptrs.emplace_back(std::make_shared<T>(std::forward<TArgs>(args)...));
}
Which can then be called as follows:
bm.add<derived_a>( "hello" ); // derived_a constructor takes a string
bm.add<derived_b>( 42 ); // derived_b constructor takes an int
Full example
#include <string>
#include <vector>
#include <memory>
class base
{
public:
virtual void f() = 0;
};
class derived_a : public base
{
public:
derived_a( std::string const& s ) : s_{ s } {}
void f() override { std::cout << "derived_a::string = " << s_ << '\n'; }
private:
std::string s_;
};
class derived_b : public base
{
public:
derived_b( int i ) : i_{ i } {}
void f() override { std::cout << "derived_b::int = " << i_ << '\n'; }
private:
int i_;
};
class base_manager
{
public:
template <typename T, typename... TArgs>
void add( TArgs&&... args )
{
ptrs.emplace_back( std::make_shared<T>( std::forward<TArgs>( args )... ) );
}
void print() { for ( auto& d : ptrs ) d->f(); }
private:
std::vector<std::shared_ptr<base>> ptrs;
};
int main()
{
base_manager bm;
bm.add<derived_a>( "hello" );
bm.add<derived_b>( 42 );
bm.print();
}
You can't pass a temporary (an r-value) to a non-const reference. Also you try to take the address of that temporary object, which will in the end produce a dangling pointer and undefined behavior.
Assuming you want to pass an object of unknown runtime type to the manager:
One thing you can do is using some sort of polymorphic copy mechanism (like a virtual clone method) and make an internal copy of the object on the heap (it has to be polymorphic, to avoid object slicing).
class base {
public:
virtual void do_stuff() = 0;
virtual shared_ptr<base> clone() const = 0;
virtual ~base()=default;
};
class derived : public base {
int data;
public:
derived() :data(0) {};
derived(const derived& other) :data(other.data)
{};
virtual shared_ptr<base> clone() const override {
return make_shared<derived>(*this);
};
void do_stuff() {/*stuff*/ }
};
class manager {
vector<shared_ptr<base>> ptrs;
public:
void add(const base& obj) {
ptrs.emplace_back(obj.clone());
}
};
int main() {
manager foo;
foo.add(derived());
}
without the clone, it would look something like this:
void add(const base& obj) {
if (typeid(obj)== typeid(derived) ){
ptrs.emplace_back(make_shared<derived>(static_cast<const derived&>(obj)));
}
else if (typeid(obj) == typeid(derived2)) {
...
}
Your original question seems to be concerned over the fact that the user/caller creates a pointer and hands it off and never deletes it. My example below, simply makes it explicit to the user that he can hand it off and forget about it. In otherwords, require the user to pass a shared_ptr...
#include <stdlib.h>
#include <vector>
#include <memory>
using namespace std;
class base{
public:
virtual void do_stuff() = 0;
};
class derived : public base{
public:
void do_stuff(){/*stuff*/ }
};
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(shared_ptr<base> ptr){
ptrs.emplace_back(ptr);
}
};
int main()
{
manager foo;
shared_ptr<derived> bp(new derived()); //require the user supply a smart pointer
foo.add(bp);
return 0;
}
This is simpler than the other posts, and may not be as forward thinking, but it does not require the derived class to implement additional base members. In many cases, it is may be enough.

Determining size of a polymorphic C++ class

Using the sizeof operator, I can determine the size of any type – but how can I dynamically determine the size of a polymorphic class at runtime?
For example, I have a pointer to an Animal, and I want to get the size of the actual object it points to, which will be different if it is a Cat or a Dog. Is there a simple way to do this, short of creating a virtual method Animal::size and overloading it to return the sizeof of each specific type?
If you know the set of possible types, you can use RTTI to find out the dynamic type by doing dynamic_cast. If you don't, the only way is through a virtual function.
Or you can use typeid, which might be faster than dynamic_cast (also with dynamic_cast you can cast to intermediary types in the hierarchy).
It looks rather bad:
#include <iostream>
#include <typeinfo>
class Creature
{
char x[4];
public:
virtual ~Creature() {}
};
class Animal: public Creature { char x[8];};
class Bird: public Creature { char x[16]; };
class Dog: public Animal { char x[32]; };
class Cat: public Animal { char x[64]; };
class Parrot: public Bird { char x[128]; };
unsigned creature_size(const Creature& cr)
{
if (typeid(cr) == typeid(Animal)) {
return sizeof (Animal);
}
else if (typeid(cr) == typeid(Dog)) {
return sizeof(Dog);
}
else if (typeid(cr) == typeid(Cat)) {
return sizeof(Cat);
}
else if (typeid(cr) == typeid(Bird)) {
return sizeof(Bird);
}
else if (typeid(cr) == typeid(Parrot)) {
return sizeof(Parrot);
}
else if (typeid(cr) == typeid(Creature)){
return sizeof(Creature);
}
assert(false && "creature_size not implemented for this type");
return 0;
}
int main()
{
std::cout << creature_size(Creature()) << '\n'
<< creature_size(Animal()) << '\n'
<< creature_size(Bird()) << '\n'
<< creature_size(Dog()) << '\n'
<< creature_size(Cat()) << '\n'
<< creature_size(Parrot()) << '\n' ;
}
For each new type you'll need to add code to the creature_size function. With a virtual size function you'll need to implement this function in each class as well. However, this function will be significantly simpler (perfectly copy-n-pasteable, which shows there might be both a limitation in the language and a problem with your code design):
virtual unsigned size() const { return sizeof(*this); }
And you can make it abstract in the base class which means that it will be a compiler error if you forget to override this method.
Edit: this is naturally assuming that given any Creature you want to know its size. If you have a strong reason to believe that you are dealing with a Dog - or a subclass of Dog (and you don't care if it is a subclass), then naturally you can use dynamic_cast for an ad hoc test.
If you are able to change source classes' design, you can totally replace dynamic polymorphism (which uses virtual functions) with static polymorphism and use the CRTP idiom:
template <class TDerived>
class Base
{
public:
int getSize()
{ return sizeof(TDerived); }
void print()
{
std::cout
<< static_cast<TDerived*>(this)->getSize()
<< std::endl;
}
int some_data;
};
class Derived : public Base<Derived>
{
public:
int some_other_data1;
int some_other_data2;
};
class AnotherDerived : public Base<AnotherDerived>
{
public:
int getSize()
{ return some_unusual_calculations(); }
// Note that the static_cast above is required for this override to work,
// because we are not using virtual functions
};
int main()
{
Derived d;
d.print();
AnotherDerived ad;
ad.print();
return 0;
}
You can do this when the needed polymorphic behavior of program can be determined at compile-time (like the sizeof case), since the CRTP has not the flexibility of dynamic polymorphism to resolve the desired object at run-time.
The static polymorphism also has the advantage of higher performance by removing virtual-function-call overhead.
If you don't want to templatize Base class or you need to hold different derived instances of Base class in a same location (like an array or a vector), you can use CRTP on a middle class and move the polymorphic behavior to that class (similar to the Polymorphic copy construction example in the Wikipedia):
class Base
{
public:
virtual int getSize() = 0;
void print()
{
std::cout << getSize() << std:endl;
}
int some_data;
};
template <class TDerived>
class BaseCRTP: public Base
{
public:
virtual int getSize()
{ return sizeof(TDerived); }
};
class Derived : public BaseCRTP<Derived>
{
// As before ...
};
class AnotherDerived : public BaseCRTP<AnotherDerived>
{
// As before ...
// Note that although no static_cast is used in print(),
// the getSize() override still works due to virtual function.
};
Base* obj_list1[100];
obj_list1[0] = new Derived();
obj_list1[2] = new AnotherDerived();
std::vector<Base*> obj_list2;
obj_list2.push_back(new Derived());
obj_list2.push_back(new AnotherDerived());
--
Update: I now found a similar but more detailed answer on stackoverflow which explains that if we further derive from the derived classes above (e.g. class FurtherDerived : public Derived {...}), the sizeof will not report correctly. He gives a more complex variant of the code to overcome this.
I can't believe that somebody's invented type_id() instead of implementing proper traits ....
One slightly convoluted way that will also work is to implement this through a Curiously Recurring Template Pattern
#include <iostream>
class Base {
public:
virtual ~Base() {}
virtual size_t getSize() = 0;
};
template <class T>
class BaseT : public Base {
public:
size_t getSize() override { return sizeof(T); }
};
class Child : public BaseT<Child> {};
int main()
{
std::unique_ptr<Base> child(new Child);
std::cout << child->getSize();
}