I have a bunch of classes which all inherit the same attributes from a common base class. The base class implements some virtual functions that work in general cases, whilst each subclass re-implements those virtual functions for a variety of special cases.
Here's the situation: I want the special-ness of these sub-classed objects to be expendable. Essentially, I would like to implement an expend() function which causes an object to lose its sub-class identity and revert to being a base-class instance with the general-case behaviours implemented in the base class.
I should note that the derived classes don't introduce any additional variables, so both the base and derived classes should be the same size in memory.
I'm open to destroying the old object and creating a new one, as long as I can create the new object at the same memory address, so existing pointers aren't broken.
The following attempt doesn't work, and produces some seemingly unexpected behaviour. What am I missing here?
#include <iostream>
class Base {
public:
virtual void whoami() {
std::cout << "I am Base\n";
}
};
class Derived : public Base {
public:
void whoami() {
std::cout << "I am Derived\n";
}
};
Base* object;
int main() {
object = new Derived; //assign a new Derived class instance
object->whoami(); //this prints "I am Derived"
Base baseObject;
*object = baseObject; //reassign existing object to a different type
object->whoami(); //but it *STILL* prints "I am Derived" (!)
return 0;
}
You can at the cost of breaking good practices and maintaining unsafe code. Other answers will provide you with nasty tricks to achieve this.
I dont like answers that just says "you should not do that", but I would like to suggest there probably is a better way to achieve the result you seek for.
The strategy pattern as suggested in a comment by #manni66 is a good one.
You should also think about data oriented design, since a class hierarchy does not look like a wise choice in your case.
Yes and no. A C++ class defines the type of a memory region that is an object. Once the memory region has been instantiated, its type is set. You can try to work around the type system sure, but the compiler won't let you get away with it. Sooner or later it will shoot you in the foot, because the compiler made an assumption about types that you violated, and there is no way to stop the compiler from making such assumption in a portable fashion.
However there is a design pattern for this: It's "State". You extract what changes into it's own class hierarchy, with its own base class, and you have your objects store a pointer to the abstract state base of this new hierarchy. You can then swap those to your hearts content.
No it's not possible to change the type of an object once instantiated.
*object = baseObject; doesn't change the type of object, it merely calls a compiler-generated assignment operator.
It would have been a different matter if you had written
object = new Base;
(remembering to call delete naturally; currently your code leaks an object).
C++11 onwards gives you the ability to move the resources from one object to another; see
http://en.cppreference.com/w/cpp/utility/move
I'm open to destroying the old object and creating a new one, as long as I can create the new object at the same memory address, so existing pointers aren't broken.
The C++ Standard explicitly addresses this idea in section 3.8 (Object Lifetime):
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object <snip>
Oh wow, this is exactly what you wanted. But I didn't show the whole rule. Here's the rest:
if:
the storage for the new object exactly overlays the storage location which the original object occupied, and
the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).
So your idea has been thought of by the language committee and specifically made illegal, including the sneaky workaround that "I have a base class subobject of the right type, I'll just make a new object in its place" which the last bullet point stops in its tracks.
You can replace an object with an object of a different type as #RossRidge's answer shows. Or you can replace an object and keep using pointers that existed before the replacement. But you cannot do both together.
However, like the famous quote: "Any problem in computer science can be solved by adding a layer of indirection" and that is true here too.
Instead of your suggested method
Derived d;
Base* p = &d;
new (p) Base(); // makes p invalid! Plus problems when d's destructor is automatically called
You can do:
unique_ptr<Base> p = make_unique<Derived>();
p.reset(make_unique<Base>());
If you hide this pointer and slight-of-hand inside another class, you'll have the "design pattern" such as State or Strategy mentioned in other answers. But they all rely on one extra level of indirection.
I suggest you use the Strategy Pattern, e.g.
#include <iostream>
class IAnnouncer {
public:
virtual ~IAnnouncer() { }
virtual void whoami() = 0;
};
class AnnouncerA : public IAnnouncer {
public:
void whoami() override {
std::cout << "I am A\n";
}
};
class AnnouncerB : public IAnnouncer {
public:
void whoami() override {
std::cout << "I am B\n";
}
};
class Foo
{
public:
Foo(IAnnouncer *announcer) : announcer(announcer)
{
}
void run()
{
// Do stuff
if(nullptr != announcer)
{
announcer->whoami();
}
// Do other stuff
}
void expend(IAnnouncer* announcer)
{
this->announcer = announcer;
}
private:
IAnnouncer *announcer;
};
int main() {
AnnouncerA a;
Foo foo(&a);
foo.run();
// Ready to "expend"
AnnouncerB b;
foo.expend(&b);
foo.run();
return 0;
}
This is a very flexible pattern that has at least a few benefits over trying to deal with the issue through inheritance:
You can easily change the behavior of Foo later on by implementing a new Announcer
Your Announcers (and your Foos) are easily unit tested
You can reuse your Announcers elsewhere int he code
I suggest you have a look at the age-old "Composition vs. Inheritance" debate (cf. https://www.thoughtworks.com/insights/blog/composition-vs-inheritance-how-choose)
ps. You've leaked a Derived in your original post! Have a look at std::unique_ptr if it is available.
You can do what you're literally asking for with placement new and an explicit destructor call. Something like this:
#include <iostream>
#include <stdlib.h>
class Base {
public:
virtual void whoami() {
std::cout << "I am Base\n";
}
};
class Derived : public Base {
public:
void whoami() {
std::cout << "I am Derived\n";
}
};
union Both {
Base base;
Derived derived;
};
Base *object;
int
main() {
Both *tmp = (Both *) malloc(sizeof(Both));
object = new(&tmp->base) Base;
object->whoami();
Base baseObject;
tmp = (Both *) object;
tmp->base.Base::~Base();
new(&tmp->derived) Derived;
object->whoami();
return 0;
}
However as matb said, this really isn't a good design. I would recommend reconsidering what you're trying to do. Some of other answers here might also solve your problem, but I think anything along the idea of what you're asking for is going to be kludge. You should seriously consider designing your application so you can change the pointer when the type of the object changes.
You can by introducing a variable to the base class, so the memory footprint stays the same. By setting the flag you force calling the derived or the base class implementation.
#include <iostream>
class Base {
public:
Base() : m_useDerived(true)
{
}
void setUseDerived(bool value)
{
m_useDerived = value;
}
void whoami() {
m_useDerived ? whoamiImpl() : Base::whoamiImpl();
}
protected:
virtual void whoamiImpl() { std::cout << "I am Base\n"; }
private:
bool m_useDerived;
};
class Derived : public Base {
protected:
void whoamiImpl() {
std::cout << "I am Derived\n";
}
};
Base* object;
int main() {
object = new Derived; //assign a new Derived class instance
object->whoami(); //this prints "I am Derived"
object->setUseDerived(false);
object->whoami(); //should print "I am Base"
return 0;
}
In addition to other answers, you could use function pointers (or any wrapper on them, like std::function) to achieve the necessary bevahior:
void print_base(void) {
cout << "This is base" << endl;
}
void print_derived(void) {
cout << "This is derived" << endl;
}
class Base {
public:
void (*print)(void);
Base() {
print = print_base;
}
};
class Derived : public Base {
public:
Derived() {
print = print_derived;
}
};
int main() {
Base* b = new Derived();
b->print(); // prints "This is derived"
*b = Base();
b->print(); // prints "This is base"
return 0;
}
Also, such function pointers approach would allow you to change any of the functions of the objects in run-time, not limiting you to some already defined sets of members implemented in derived classes.
There is a simple error in your program. You assign the objects, but not the pointers:
int main() {
Base* object = new Derived; //assign a new Derived class instance
object->whoami(); //this prints "I am Derived"
Base baseObject;
Now you assign baseObject to *object which overwrites the Derived object with a Base object. However, this does work well because you are overwriting an object of type Derived with an object of type Base. The default assignment operator just assigns all members, which in this case does nothing. The object cannot change its type and still is a Derived objects afterwards. In general, this can leads to serious problems e.g. object slicing.
*object = baseObject; //reassign existing object to a different type
object->whoami(); //but it *STILL* prints "I am Derived" (!)
return 0;
}
If you instead just assign the pointer it will work as expected, but you just have two objects, one of type Derived and one Base, but I think you want some more dynamic behavior. It sounds like you could implement the specialness as a Decorator.
You have a base-class with some operation, and several derived classes that change/modify/extend the base-class behavior of that operation. Since it is based on composition it can be changed dynamically. The trick is to store a base-class reference in the Decorator instances and use that for all other functionality.
class Base {
public:
virtual void whoami() {
std::cout << "I am Base\n";
}
virtual void otherFunctionality() {}
};
class Derived1 : public Base {
public:
Derived1(Base* base): m_base(base) {}
virtual void whoami() override {
std::cout << "I am Derived\n";
// maybe even call the base-class implementation
// if you just want to add something
}
virtual void otherFunctionality() {
base->otherFunctionality();
}
private:
Base* m_base;
};
Base* object;
int main() {
Base baseObject;
object = new Derived(&baseObject); //assign a new Derived class instance
object->whoami(); //this prints "I am Derived"
// undecorate
delete object;
object = &baseObject;
object->whoami();
return 0;
}
There are alternative patterns like Strategy which implement different use cases resp. solve different problems. It would probably good to read the pattern documentation with special focus to the Intent and Motivation sections.
I would consider regularizing your type.
class Base {
public:
virtual void whoami() { std::cout << "Base\n"; }
std::unique_ptr<Base> clone() const {
return std::make_unique<Base>(*this);
}
virtual ~Base() {}
};
class Derived: public Base {
virtual void whoami() overload {
std::cout << "Derived\n";
};
std::unique_ptr<Base> clone() const override {
return std::make_unique<Derived>(*this);
}
public:
~Derived() {}
};
struct Base_Value {
private:
std::unique_ptr<Base> pImpl;
public:
void whoami () {
pImpl->whoami();
}
template<class T, class...Args>
void emplace( Args&&...args ) {
pImpl = std::make_unique<T>(std::forward<Args>(args)...);
}
Base_Value()=default;
Base_Value(Base_Value&&)=default;
Base_Value& operator=(Base_Value&&)=default;
Base_Value(Base_Value const&o) {
if (o.pImpl) pImpl = o.pImpl->clone();
}
Base_Value& operator=(Base_Value&& o) {
auto tmp = std::move(o);
swap( pImpl, tmp.pImpl );
return *this;
}
};
Now a Base_Value is semantically a value-type that behaves polymorphically.
Base_Value object;
object.emplace<Derived>();
object.whoami();
object.emplace<Base>();
object.whoami();
You could wrap a Base_Value instance in a smart pointer, but I wouldn't bother.
I don’t disagree with the advice that this isn’t a great design, but another safe way to do it is with a union that can hold any of the classes you want to switch between, since the standard guarantees it can safely hold any of them. Here’s a version that encapsulates all the details inside the union itself:
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <new>
#include <typeinfo>
class Base {
public:
virtual void whoami() {
std::cout << "I am Base\n";
}
virtual ~Base() {} // Every base class with child classes that might be deleted through a pointer to the
// base must have a virtual destructor!
};
class Derived : public Base {
public:
void whoami() {
std::cout << "I am Derived\n";
}
// At most one member of any union may have a default member initializer in C++11, so:
Derived(bool) : Base() {}
};
union BorD {
Base b;
Derived d; // Initialize one member.
BorD(void) : b() {} // These defaults are not used here.
BorD( const BorD& ) : b() {} // No per-instance data to worry about!
// Otherwise, this could get complicated.
BorD& operator= (const BorD& x) // Boilerplate:
{
if ( this != &x ) {
this->~BorD();
new(this) BorD(x);
}
return *this;
}
BorD( const Derived& x ) : d(x) {} // The constructor we use.
// To destroy, be sure to call the base class’ virtual destructor,
// which works so long as every member derives from Base.
~BorD(void) { dynamic_cast<Base*>(&this->b)->~Base(); }
Base& toBase(void)
{ // Sets the active member to b.
Base* const p = dynamic_cast<Base*>(&b);
assert(p); // The dynamic_cast cannot currently fail, but check anyway.
if ( typeid(*p) != typeid(Base) ) {
p->~Base(); // Call the virtual destructor.
new(&b) Base; // Call the constructor.
}
return b;
}
};
int main(void)
{
BorD u(Derived{false});
Base& reference = u.d; // By the standard, u, u.b and u.d have the same address.
reference.whoami(); // Should say derived.
u.toBase();
reference.whoami(); // Should say base.
return EXIT_SUCCESS;
}
A simpler way to get what you want is probably to keep a container of Base * and replace the items individually as needed with new and delete. (Still remember to declare your destructor virtual! That’s important with polymorphic classes, so you call the right destructor for that instance, not the base class’ destructor.) This might save you some extra bytes on instances of the smaller classes. You would need to play around with smart pointers to get safe automatic deletion, though. One advantage of unions over smart pointers to dynamic memory is that you don’t have to allocate or free any more objects on the heap, but can just re-use the memory you have.
DISCLAIMER: The code here is provided as means to understand an idea, not to be implemented in production.
You're using inheritance. It can achieve 3 things:
Add fields
Add methods
replace virtual methods
Out of all those features, you're using only the last one. This means that you're not actually forced to rely on inheritance. You can get the same results by many other means. The simplest is to keep tabs on the "type" by yourself - this will allow you to change it on the fly:
#include <stdexcept>
enum MyType { BASE, DERIVED };
class Any {
private:
enum MyType type;
public:
void whoami() {
switch(type){
case BASE:
std::cout << "I am Base\n";
return;
case DERIVED:
std::cout << "I am Derived\n";
return;
}
throw std::runtime_error( "undefined type" );
}
void changeType(MyType newType){
//insert some checks if that kind of transition is legal
type = newType;
}
Any(MyType initialType){
type = initialType;
}
};
Without inheritance the "type" is yours to do whatever you want. You can changeType at any time it suits you. With that power also comes responsibility: the compiler will no longer make sure the type is correct or even set at all. You have to ensure it or you'll get hard to debug runtime errors.
You may wrap it in inheritance just as well, eg. to get a drop-in replacement for existing code:
class Base : Any {
public:
Base() : Any(BASE) {}
};
class Derived : public Any {
public:
Derived() : Any(DERIVED) {}
};
OR (slightly uglier):
class Derived : public Base {
public:
Derived : Base() {
changeType(DERIVED)
}
};
This solution is easy to implement and easy to understand. But with more options in the switch and more code in each path it gets very messy. So the very first step is to refactor the actual code out of the switch and into self-contained functions. Where better to keep than other than Derivied class?
class Base {
public:
static whoami(Any* This){
std::cout << "I am Base\n";
}
};
class Derived {
public:
static whoami(Any* This){
std::cout << "I am Derived\n";
}
};
/*you know where it goes*/
switch(type){
case BASE:
Base:whoami(this);
return;
case DERIVED:
Derived:whoami(this);
return;
}
Then you can replace the switch with an external class that implements it via virtual inheritance and TADA! We've reinvented the Strategy Pattern, as others have said in the first place : )
The bottom line is: whatever you do, you're not inheriting the main class.
you cannot change to the type of an object after instantiation, as you can see in your example you have a pointer to a Base class (of type base class) so this type is stuck to it until the end.
the base pointer can point to upper or down object doesn't mean changed its type:
Base* ptrBase; // pointer to base class (type)
ptrBase = new Derived; // pointer of type base class `points to an object of derived class`
Base theBase;
ptrBase = &theBase; // not *ptrBase = theDerived: Base of type Base class points to base Object.
pointers are much strong, flexible, powerful as much dangerous so you should handle them cautiously.
in your example I can write:
Base* object; // pointer to base class just declared to point to garbage
Base bObject; // object of class Base
*object = bObject; // as you did in your code
above it's a disaster assigning value to un-allocated pointer. the program will crash.
in your example you escaped the crash through the memory which was allocated at first:
object = new Derived;
it's never good idea to assign a value and not address of a subclass object to base class. however in built-in you can but consider this example:
int* pInt = NULL;
int* ptrC = new int[1];
ptrC[0] = 1;
pInt = ptrC;
for(int i = 0; i < 1; i++)
cout << pInt[i] << ", ";
cout << endl;
int* ptrD = new int[3];
ptrD[0] = 5;
ptrD[1] = 7;
ptrD[2] = 77;
*pInt = *ptrD; // copying values of ptrD to a pointer which point to an array of only one element!
// the correct way:
// pInt = ptrD;
for(int i = 0; i < 3; i++)
cout << pInt[i] << ", ";
cout << endl;
so the result as not as you guess.
I have 2 solutions. A simpler one that doesn't preserve the memory address, and one that does preserve the memory address.
Both require that you provide provide downcasts from Base to Derived which isn't a problem in your case.
struct Base {
int a;
Base(int a) : a{a} {};
virtual ~Base() = default;
virtual auto foo() -> void { cout << "Base " << a << endl; }
};
struct D1 : Base {
using Base::Base;
D1(Base b) : Base{b.a} {};
auto foo() -> void override { cout << "D1 " << a << endl; }
};
struct D2 : Base {
using Base::Base;
D2(Base b) : Base{b.a} {};
auto foo() -> void override { cout << "D2 " << a << endl; }
};
For the former one you can create a smart pointer that can seemingly change the held data between Derived (and base) classes:
template <class B> struct Morpher {
std::unique_ptr<B> obj;
template <class D> auto morph() {
obj = std::make_unique<D>(*obj);
}
auto operator->() -> B* { return obj.get(); }
};
int main() {
Morpher<Base> m{std::make_unique<D1>(24)};
m->foo(); // D1 24
m.morph<D2>();
m->foo(); // D2 24
}
The magic is in
m.morph<D2>();
which changes the held object preserving the data members (actually uses the cast ctor).
If you need to preserve the memory location, you can adapt the above to use a buffer and placement new instead of unique_ptr. It is a little more work a whole lot more attention to pay to, but it gives you exactly what you need:
template <class B> struct Morpher {
std::aligned_storage_t<sizeof(B)> buffer_;
B *obj_;
template <class D>
Morpher(const D &new_obj)
: obj_{new (&buffer_) D{new_obj}} {
static_assert(std::is_base_of<B, D>::value && sizeof(D) == sizeof(B) &&
alignof(D) == alignof(B));
}
Morpher(const Morpher &) = delete;
auto operator=(const Morpher &) = delete;
~Morpher() { obj_->~B(); }
template <class D> auto morph() {
static_assert(std::is_base_of<B, D>::value && sizeof(D) == sizeof(B) &&
alignof(D) == alignof(B));
obj_->~B();
obj_ = new (&buffer_) D{*obj_};
}
auto operator-> () -> B * { return obj_; }
};
int main() {
Morpher<Base> m{D1{24}};
m->foo(); // D1 24
m.morph<D2>();
m->foo(); // D2 24
m.morph<Base>();
m->foo(); // Base 24
}
This is of course the absolute bare bone. You can add move ctor, dereference operator etc.
#include <iostream>
class Base {
public:
virtual void whoami() {
std::cout << "I am Base\n";
}
};
class Derived : public Base {
public:
void whoami() {
std::cout << "I am Derived\n";
}
};
Base* object;
int main() {
object = new Derived;
object->whoami();
Base baseObject;
object = &baseObject;// this is how you change.
object->whoami();
return 0;
}
output:
I am Derived
I am Base
Your assignment only assigns member variables, not the pointer used for virtual member function calls. You can easily replace that with full memory copy:
//*object = baseObject; //this assignment was wrong
memcpy(object, &baseObject, sizeof(baseObject));
Note that much like your attempted assignment, this would replace member variables in *object with those of the newly constructed baseObject - probably not what you actually want, so you'll have to copy the original member variables to the new baseObject first, using either assignment operator or copy constructor before the memcpy, i.e.
Base baseObject = *object;
It is possible to copy just the virtual functions table pointer but that would rely on internal knowledge about how the compiler stores it so is not recommended.
If keeping the object at the same memory address is not crucial, a simpler and so better approach would be the opposite - construct a new base object and copy the original object's member variables over - i.e. use a copy constructor.
object = new Base(*object);
But you'll also have to delete the original object, so the above one-liner won't be enough - you need to remember the original pointer in another variable in order to delete it, etc. If you have multiple references to that original object you'll need to update them all, and sometimes this can be quite complicated. Then the memcpy way is better.
If some of the member variables themselves are pointers to objects that are created/deleted in the main object's constructor/destructor, or if they have a more specialized assignment operator or other custom logic, you'll have some more work on your hands, but for trivial member variables this should be good enough.
Related
I try to have an abstract base class act like an interface and instantiate a derived class based on user input. I tried to implement it like this
class A
{
public:
virtual void print() = 0;
};
class B : A
{
public:
void print() override { cout << "foo"; }
};
class C : A
{
public:
void print() override { cout << "bar"; }
};
int main()
{
bool q = getUserInput();
A a = q ? B() : C();
a.print();
}
But that does not work. I’m coming from c# and that would be valid c# so I’m looking for an equivalent way of implement it in c++. Could someone please give me a hint? Thanks!
There are two problems with the code in its current state.
By default in C++, a class that inherits from a class or struct will be private inheritance. E.g. when you say class B : A, it's the same as writing class B : private A -- which in C++ restricts the visibility of this relationship only to B and A.
This is important because it means that you simply cannot upcast to an A from outside the context of these classes.
You are trying to upcast an object rather than a pointer or reference to an object. This fundamentally cannot work with abstract classes and will yield a compile-error even if the code was well formed.
If the base class weren't abstract, then this would succeed -- but would perform object slicing which prevents the virtual dispatch that you would expect (e.g. it won't behave polymorphically, and any data from the derived class is not present in the base class).
To fix this, you need to change the inheritance to explicitly be public, and you should be using either pointers or references for the dynamic dispatch. For example:
class A
{
public:
virtual void print() = 0;
};
class B : public A
// ^~~~~~
{
public:
void print() override { cout << "foo"; }
};
class C : public A
// ^~~~~~
{
public:
void print() override { cout << "bar"; }
};
To model something closer to the likes of C#, you will want to construct a new object. With the change above to public, it should be possible to use std::unique_ptr (for unique ownership) or std::shared_ptr (for shared ownership).
After this, you can simply do:
int main() {
auto a = std::unique_ptr<A>{nullptr};
auto q = getUserInput();
if (q) { // Note: ternary doesn't work here
a = std::make_unique<B>();
} else {
a = std::make_unique<C>();
}
}
However, note that when owning pointers from an abstract base class, you will always want to have a virtual destructor -- otherwise you may incur a memory leak:
class A {
public:
...
virtual ~A() = default;
};
You can also do something similar with references if you don't want to use heap memory -- at which point the semantics will change a little bit.
References in C++ can only refer to an object that already has a lifetime (e.g. has been constructed), and can't refer to a temporary. This means that you'd have to have instances of B and C to choose from, such as:
int main() {
auto b = B{};
auto c = C{};
bool q = getUserInput();
A& a = q ? b : c;
a.print(); // A& references either 'b' or 'c'
}
You need to use pointers :
A* a = q ? static_cast<A*>(new B) : new C;
...
delete a;
A ternary is also a special case here, as it takes the type of the first expression.
If C inherited from B here it would not be a problem.
I've been struggling with with this C++ thing for a while. I've created base object class and derived object class and I'm trying to store references to both base and derived objects in a vector of base-class pointers (avoid object slicing).
With pointer, I am able to run virtual methods and I can confirm that pointer points to derived-class object, however I cannot get to derived class specific variables. Is there any way of doing it ?
Base class object:
class Base
{
public:
Manager* manager;
Base(){}
Base(Manager* mManager){
manager = mManager;
}
virtual void init(){}
virtual void speak() {
std::cout << "Base class is speaking!" << std::endl;
}
};
Derived class object:
class Derived : public Base
{
public:
Manager* manager;
int DerviedVariable = 100;
Derived(){}
Derived(Manager* mManager){
manager = mManager;
}
void speak() override {
std::cout << "Derived class is speaking!" << std::endl;
}
};
Those objects (Base na Derived) are created and stored using Manager class and array called groupedEntities :
constexpr std::size_t maxGroups = 32;
using Group = std::size_t;
class Manager
{
public:
std::array<std::vector<Base*>, maxGroups> groupedEntities;
void addToGroup(Base* mBase, Group mGroup)
{
groupedEntities[mGroup].emplace_back(mBase);
}
std::vector<Base*>& getGroup(Group mGroup)
{
return groupedEntities[mGroup];
}
template <typename T, typename... TArgs>
T* addEnt(TArgs&&... mArgs)
{
T* e(new T(this));
return e;
}
};
I am create objects and try to reference them like that :
void main() {
std:size_t groupBlob = 0u;
Manager* manager = new Manager();
Derived* blob1(manager->addEnt<Derived>());
Derived* blob2(manager->addEnt<Derived>());
manager->addToGroup(blob1, groupBlob);
manager->addToGroup(blob2, groupBlob);
auto& grouped(manager->getGroup(groupBlob));
for (auto& e : grouped)
{
e->speak();
std::cout << e.DerviedVariable ;
}
}
Unfortunately, e.DerviedVariable is inaccessible, whereas speak() function says "Dervied class is speaking". Is there any way to access Derived-class variables with this architecture? Thanks
Yes it is possible. You only need to cast the pointer. The simplest syntax is:
((Derived*)e)->DerviedVariable
which is equivalent (modulo casting away constness, if any) to C++ish
static_cast<Derived*>(e)->DerviedVariable
The word “static” here reminds that there is no runtime checking: the compiler trusts you that e indeed points to an instance of Derived. If it doesn’t, undefined behavior occurs. The safer alternative is dynamic_cast:
Derived *ee = dynamic_cast<Derived*>(e);
if (ee)
x = ee->DerviedVariable;
It returns NULL if the object is not an instance of Derived. (Note that references can be casted as well, but as there is no NULL reference, dynamic_cast will throw instead if cast is not possible)
Nevertheless, using such casts is often considered a bad practice, for a reason. Virtual functions are preferable, mostly because using them don’t require you to even know the actual object type at the call point.
You can use dynamic_cast in such cases. The expression dynamic_cast<Derived*>(e) where e is of type Base* will evaluate to a Derived* if e does in fact point to an object of Derived type, otherwise it will evaluate to a null pointer.
if(Derived* d = dynamic_cast<Derived*>(e)) {
std::cout << d->e.DerviedVariable;
}
I have a function that accepts a shared pointer of type Base and then std::dynamic_pointer_cast to a derived type. However, the derived pointer is a NULL and I can't see why. I have made sure to include a virtual destructor in my base class. I do not want to use a static cast as this cannot guarantee that my derived member variables and functions are preserved?
The code is as follows:
Base Class:
class Base
{
public:
mType get_type()
{
return msg_type;
}
void set_type(mType type)
{
msg_type = type;
}
virtual ~cMsg() = default;
protected:
mType msg_type;
message msg;
};
Derived Class:
class Derived : public Base
{
public:
void set_i(int j)
{
i = j;
}
int get_i()
{
return i;
}
private:
int i;
};
Function performing cast:
void callback(std::shared_ptr<Base> msg_received)
{
std::cout<< "Callback called\n";
auto real_msg = std::dynamic_pointer_cast<Derived>(msg_received);
if (real_msg != NULL)
{
std::cout << "i value is: " << real_msg->get_i() << "\n";
}
}
Function creating the Derived object and calling the function:
int main()
{
Derived test_msg;
test_msg.set_i(1);
test_msg.set_type(mSystem::TEST_MSG);
std::shared_ptr<Base> msg_ptr = std::make_shared<Base>(test_msg);
callback(msg_ptr);
return 0;
}
Any help would be appreciated.
Edit: Corrected typo
You're totally slicing. Your dynamically allocated object (managed by that shared pointer) is just a Base, copy constructed from a Derived. You can't "get the Derived back" afterwards any more than you can design a sports car with construction plans only for one of its wheels.
I think your key confusion here is in thinking that make_shared makes something shared. It doesn't. It makes something new that will be shared.
You are making shared_ptr of type Base, even if you provide it with object of type Derived. Keep in mind, all make_shared does (after allocating memory using allocator) is calling a constructor of type specified with the arguments provided to make_shared.
In your case, it creates an object of type Base, and gives it an instance of Derived. Base copy constructor is than called, passed Derived object implicitly converted to the const reference to Base.
I would like to force a certain API for all classes derived from the base class. Normally, you do that using an abstract base class that has purely virtual functions. However, how do you handle functions that return the derived type? How do I go about forcing that type of function?
struct base
{
virtual base func() = 0;
};
struct deriv1 : base
{
deriv1 func();
};
struct deriv2 : base
{
deriv2 func();
};
This example will give an error like "invalid abstract return type for member function". I've seen some answers that suggest returning pointers, but I don't particularly want to dip into dynamic memory for that and keeping track of all the allocated pointers would be a special kind of hell. Any ideas?
When a virtual function returns a pointer or reference to a class, a class which inherits from the base class and overrides the function is allowed to change the return type to a pointer or reference to a class which is derived from the original return type.
You can't return base by value as it is abstract so you can't actually create one by itself.
http://en.wikipedia.org/wiki/Covariant_return_type
When using virtual functions and base classes, you usually have to use dynamic allocation to create your objects. I suggest you look into smart pointers to help manage the memory.
In your example, the func won't be "the same function", so the deriv1 and deriv2 variants won't have a different virtual function.
Unfortunately, there is no other alternative than to return a pointer - it doesn't have to be a pointer to dynamically allocated memory (you could for example return a pointer to this or a static deriv2 anObject; - but it needs to be a pointer to base. [Or a reference, but the same problem applies].
The main reason for this (aside from the fact that "functions can't be differentiated only on return type") is that if you have some generic code that looks something like this:
vector<base*> v;
... stuff a bunch of `dervi1` or `deriv2` objects into v.
for(i : v)
{
base b = i->func();
}
Now, either you have now cut off [sliced] your deriv1 or deriv2 into the size of a base, or you'd have copied an object that is larger than base into a base-size object - neither of which will be of any benefit whatsoever. [I'm assuming that in the REAL use-case for this, deriv1 and deriv2 are in fact different from base by more aspects than the name of the object - otherwise, it's quite pointless. And that deriv1 and deriv2 are inheriting from base, of course].
In other words, you can't copy an object of unknown type with =. And it's absolutely no point in having a virtual function if you have to know what type it returns.
Basically a way of saying "If you want to replace deriv1 with deriv2 in your code, you need to implement these functions"
From your quote here above, it looks like you want something like this:
#include <memory> //for unique_ptr
#include <iostream>
struct Base
{
virtual void doX() = 0;
virtual void doY() = 0;
virtual ~Base(){}
};
struct D1 : Base
{
virtual void doX()
{
std::cout << "D1::doX()" << std::endl;
}
virtual void doY()
{
std::cout << "D1::doY()" << std::endl;
}
};
struct D2 : D1
{
virtual void doX()
{
std::cout << "D2::doX()" << std::endl;
}
virtual void doY()
{
std::cout << "D2::doY()" << std::endl;
}
};
//From this point on you can do various things:
void driver()
{
Base* base = new D1;//
base->doX(); //Calls D1::doX()
D1* d1 = new D2;
d1->doX(); //Calls D2::doX()
}
// or...
void driver( Base* base )
{
//A way to replace Base with D1 with D2 depending
// on how driver was called.
}
//Finally, maybe you want a factory to create the correct
// derived type based on which factory was instantiated.
// Creates family of products, each item representing the base
// in it's hierarchy - only one shown here...
struct AbstractFactory
{
virtual std::unique_ptr<Base> create() const = 0;
protected:
virtual ~AbstractFactory(){}
};
struct D1Factory : AbstractFactory
{
//Doesn't matter if <Derived> is returned, because it adheres
// to interface of Base (isA base), and correct functions are
// found polymorphically
virtual std::unique_ptr<Base> create() const
{
return std::unique_ptr<Base>( new D1 );
}
};
struct D2Factory : AbstractFactory
{
//Doesn't matter if <Derived> is returned, because it adheres
// to interface of Base (isA base), and correct functions are
// found polymorphically
virtual std::unique_ptr<Base> create() const
{
return std::unique_ptr<Base>( new D2 );
}
};
void driver( const AbstractFactory& factory )
{
std::unique_ptr<Base> base( factory.create() );
base->doX();
base->doY();
//Memory deallocated automagically...
}
int main()
{
driver( D1Factory() );
driver( D2Factory() );
}
You'll see that this holds true to your quote. D2 replaces D1
seamlessly from the perspective of driver...
This is a basic concept question. If I have a class that Derived that inherits from Base, and I instantiate a new Derived object, can I set it's Base object to a specific Base object of my choosing so that all calls base class methods are redirected to this particular base object?
something like this:
class Base
{
protected:
string name;
public:
Base(string n) { name = n}
void doSomething(){cout << name << "\n";}
};
class Derived : public Base
{
public:
Derived(string n) : Base(n) {}
int main()
{
Derived* d = new Derived("original base"); //create a derived
d->doSomething(); // prints "original base"
Base* rB = new Base("replacement base"); // create a new base object
((Base*) d) = rB; // replace the base object of d with a new one (pretend code)
d->doSomething(); // prints "replacement base"
return 0;
}
I'm sure I made all sorts of errors in that simple code, because my skill level is low, but just for the idea.
Is this possible in C++? We can slice the derived information off of an object, so can we separate and replace the components in a chain of inheritance?
Why would I want to do this?
Consider the mixin lilies: (again, forgive syntax errors)
template <class T> class MyMixin : public T
{
public:
MyMixin(T desiredBaseObject)
{
// do something to set the desired base
// object of this class to desiredBaseObject.
}
};
RandomClass1 dog(int i = 0);
RandomClass2 cat(double i = 0.0);
MyMixin< RandomClass1 > mixin1(dog);
MyMixin< RandomClass2 > mixin2(cat);
In this case, if we could set the base object of the mixin to any desired object, we could use constructors with any parameter list in our mixin without the mixin needing to know anything about it. Also, the mixin could be used like a decorator without the need for a common interface amongst decorators.
Thanks for the answers. Since we can slice off the derived part of an object, it seems like the base and derived information lives separately. Could someone comment on this? Could we access some internal table, like the vtables I hear so much about (I don't know anything about this type of stuff, so maybe this is not applicable), and accomplish this?
#Benoît
Could you explain why only 1 and 4 work, but 2 and 3 do not?
class Base
{
protected:
std::string name;
public:
Base(std::string n)
{
name = n;
}
virtual void doSomething()
{
cout << name << "\n";
}
};
class Derived : public Base
{
public:
int x;
Derived(std::string n) : Base(n)
{
x = 5;
}
void printX()
{
cout << "x = " << x << "\n";
x++;
}
};
Derived* d1 = new Derived("original 1");
d1->doSomething();
d1->printX();
Base* rb1 = new Base("new 1");
*static_cast<Base*>(d1) = *rb1;
d1->doSomething();
d1->printX();
cout << "\n\n";
Derived d2 = Derived("original 2");
d2.doSomething();
d2.printX();
Base b2 = Base("new 2");
static_cast<Base>(d2) = b2;
d2.doSomething();
d2.printX();
cout << "\n\n";
Derived d3("original 3");
d3.doSomething();
d3.printX();
Base b3("new 3");
static_cast<Base>(d3) = b3;
d3.doSomething();
d3.printX();
cout << "\n\n";
Derived d4("original 4");
d4.doSomething();
d4.printX();
Base b4("new 4");
*static_cast<Base*>(&d4) = *&b4;
d4.doSomething();
d4.printX();
cout << "\n\n";
this will print:
original 1
x = 5
new 1
x = 6
original 2
x = 5
original 2
x = 6
original 3
x = 5
original 3
x = 6
original 4
x = 5
new 4
x = 6
Why does this only work with when using a pointer?
I'm not questioning why you want to do this, but it's perfectly safe do it unless your inheritance breaks the ISA relationship (eg Derived is a restricted subset of Base, eg a Square is not a Rectangle since it is possible to resize only one dimension of a Rectangle but impossible to do so with a Square).
*static_cast<Base*>(d) = *rB;
(works also with references)
or you can write a little function (you will find lots of functions doing this):
template<typename T>
T& assign(T& to, const T& from)
{
return to = from;
}
assign<Base>(*d, *rB);
and anyway, you do this every time you overload/redefine operator=
Derived& operator=(const Derived& other)
{
// prettier than the cast notation
Base::operator=(other);
// do something specific to Derived;
this->name += " (assigned)";
return *this;
}
No. If you need to do this, you should use composition, not inheritance.
(I'm answering the more general question -- in your specific case where you just want to change the string you can just change name from within the derived class)
Inheritance = IS A relation.
Composition = HAS A relation.
You're describing a class that has an object of type A where you can set its instance.
So you need to use composition - Make a class that hold a member of type A
Inheritance is a property of types, not of objects. The type "Derived" inherits from the type "Base". You can make objects of type "Derived" (Derived x;), and you can also make objects of type "Base" (Base y, unless that's forbidden), but each of those objects are complete, fully-fledged objects with no "replaceable parts".
The point of type inheritance is that you may treat an object of type "Derived" as if it was an object of type "Base" (as long as you refer to it by reference or pointer), that is, if you have a function void foo(Base & b);, then you may call foo(x). But foo can only access those parts of x which are inherited from "Base"!
You could combine inheritance & composition:
class A {
string name;
public: A(const char* s) : name(string(s)) {}
virtual void m() { cout << name << endl; }
};
class B : A {
public:
B(const char* s) : A(s), a(0) {}
void m() { if (a) a->m(); else A::m(); }
A* a;
};
int main() {
B b("b");
b.m(); // prints b
b.a = new A("a");
b.m(); // prints a
}
No, you cannot do that.
You have (at least) a couple of options:
Create a new Derived object, parameterised by a mixture of parameters from the two objects you wish to combine.
Create some setter methods in the Base class, that allow you to change its parameters/state later in its lifetime.
No.
Why would you want to do this? If two Deriveds are supposed to have the exact same Base, such that modifications through one Derived show up in the other, you need to have some sort of pointer to Base in each derived, making this composition, not inheritance.
If you want to change the data in the Derived's Base, write a function to do that, a little like a copy assignment operator for Base.
Alternately, you could make a new constructor for Derived that would take a Base and a Derived, and take Base information from the Base and Derived information from the Derived.