-2

I got this code:

#include <iostream>
#include <string>

using namespace std;

struct Base {
  Base(string name) {
    this->name = name;
  }
  string name;
};

struct Derived: Base {
  string name2;
};

template <typename T>
T createNode(string name) {
  Base* node = new Base(name);
  return static_cast<T>(node);
}

int main() {
  Derived* node = createNode<Derived*>("hej");
  node->name2 = "bajs";
  cout << node->name2;
}

And the node->name2 = "bajs"; line causes (random) segmentation fault. I'm just wondering how I can correct this to not cause segmentation fault. I still want to call createNode() to create the base node and set all the property members after. Is it doable in c++?

einstein
  • 13,389
  • 27
  • 80
  • 110
  • why are you mixing templates and inheritance this way? if `createNode` is a template , then you shouldn't be creating a `new Base` in it. If you want inheritance remove the template and have the method return `Base` – ZivS Apr 05 '15 at 07:58
  • It is hard to undersatnd why derived class has `string name2;`. Also I think `createNode` should use `T` instead of `Base` in statement `Base* node = new Base(name);` – VolAnd Apr 05 '15 at 07:59
  • You can't just case a pointer to a base object to pointer to derived type and expect it to work. The pointed to object is still a `Base`. It does not have a `name2` member. – juanchopanza Apr 05 '15 at 08:03
  • I guess re-reading the text book on C++ is the order of the day – Ed Heal Apr 05 '15 at 08:04
  • 2
    Saying "poo" in a program is so funny and awesome and really mature. – molbdnilo Apr 05 '15 at 08:07
  • This is nearly the same as your previous question... to which I answered that you need to do `new decltype(*T)`, not `new Base` – M.M Apr 05 '15 at 08:21
  • @MattMcNabb can you give me an example I tried `new decltype(*T)`. But it gives me `'T' does not refer to a value`? – einstein Apr 05 '15 at 08:24
  • sorry, try `decltype(*(T{}))` . This'd be a lot easier if you made your template parameter be the type, instead of the pointer to the type – M.M Apr 05 '15 at 08:29
  • @MattMcNabb it stills give me an error `cannot allocate reference type 'decltype(*(Derived *({ })))'` – einstein Apr 05 '15 at 08:41
  • just use the type as the template parameter – M.M Apr 05 '15 at 08:50

2 Answers2

2

This bit of code:

template <typename T>
T createNode(string name) {
  Base* node = new Base(name);
  return static_cast<T>(node);
}

creates an object of type Base.

This:

  Derived* node = createNode<Derived*>("hej");
  node->name2 = "najs";    // No need to use rude words, even if you think most people can't read them.

Uses the created object as Derived. Since Derived requires more space than Base, when you use name2, you are overwriting something outside of the object created in createNode. name2 also hasn't been constructed, meaning the assignment most likely uses random garbage values, which could well in itself cause a crash.

You will need to rearrange your code such that it creates the correct object first, and if you want to use a constructor, you need to have a constructor for Derived that takes the named object. [There are some other ways to achieve this too, but typically not what you want here]

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • thanks for your explanation. I will user more najser words in the future. But isn't there anyway I can create the base class with a function that sets the base properties and then add properties to this object? My base class contains a lot of properties the could be inherited. – einstein Apr 05 '15 at 08:22
  • @einstein Maybe you're looking for the Decorator Pattern? http://stackoverflow.com/questions/2988066/decorator-pattern-in-c – PaulMcKenzie Apr 05 '15 at 08:31
  • Simply put, no. There are various ways that you can "add things" to other other things - the decorator pattern is one, having a container type (`vector`, `map` or similar) inside the class is another. Which is most suitable depends on what you are actually trying to achieve. – Mats Petersson Apr 05 '15 at 12:09
1

Perhaps, I do not understand the idea of your program, but I think, it have to be like that:

#include <iostream>
#include <string>

using namespace std;

struct Base {
  Base(string name) {
    this->name = name;
  }
  string name;
};

struct Derived: Base {
    Derived(string name):Base(name)
    {
    }
    // string name2; // it is not needed
};

template <typename T>
T* createNode(string name) {
  T* node = new T(name);
  return node;
}

int main() {
  Derived* node = createNode<Derived>("hej");
  node->name = "bajs";
  cout << node->name;
}
VolAnd
  • 6,367
  • 3
  • 25
  • 43
  • I want the `createNode()` to create the base class and then just add pops to it, because I want my program to be DRY. The base class contains many props that could be inherited by any derived classes. – einstein Apr 05 '15 at 08:31
  • @einstein C++ has a type system , once an object is created it cannot change type or add new fields or anything – M.M Apr 05 '15 at 08:32
  • @einstein : But in your code, you create element of base class and are trying to use field that is not exist in the base class. – VolAnd Apr 05 '15 at 08:33
  • @VolAnd thanks for the explanation. I just used your example and correct it to fit my purpose a bit. – einstein Apr 05 '15 at 08:44