0
votes

I have a abstract base class that hold data, and I need allocate memory to these data, and the other problem is that derivate class has the = operator overloaded and copy constructor, I would like to know how Can I assure that in the derivate class copy the members data from abstract base class will be copied too, follows the code exemple:

class A {
public:
  A(const char* v) {
    value = new char[strlen(v)+1];
    strncpy(value, v, strlen(v));
  }

  A(const A &a) {
    value = new char[strlen(a.value)+1];
    strncpy(value, a.value, strlen(a.value));
  }

  virtual ~A() {
    delete[] value;
  }

  A& operator=(const A& a) {
    value = new char[strlen(a.value)+1];
    strncpy(value, a.value, strlen(a.value));
    return *this;
  }

  const char* get() const {
    return value;
  }

  virtual void do_some() = 0;
private:
  char *value;
};

class B: public A {
public:
  B(const char *v, const char *n) : A(v) {
    name = new char[strlen(n)+1];
    strncpy(name, n, strlen(n));
  }

  B(const B &b) : A(b) {
    name = new char[strlen(b.name)+1];
    strncpy(name, b.name, strlen(b.name));
  }

  ~B() {
    delete[] name;
  }

  B& operator=(const B& b) {
    A::operator=(b);
    name = new char[strlen(b.name)+1];
    strncpy(name, b.name, strlen(b.name));
    return *this;
  }

  const char *get() const {
    return name;
  }

  void do_some() {
    std::cout << name << std::endl;
  }

private:
  char *name;
};

My doubts is, in some C++'s books says that is not a good idea to overload the operator = and declare a copy constructor in abstract base class, so how can I declare a copy constructor and operator= in derivate class and assure that the base class was copied properly?

In my project if I don't use data members at the abstract base class, I have to declare some data members in all derivate class, of course that is more than one, so I designed the abstract class with data member, but I don't know if is the better way to do.

1
Related: I would be doubting your strncpy calls everywhere. They're wrong, as they never initialize the terminator. The very nature of how you have structured the length-parameter means strncpy cannot terminate the string. And ultimately strncpy isn't needed here anyway. You know you just allocated the proper length to take the target and its terminator, so literally a strcpy, or even a memcpy would suffice. - WhozCraig
Apart from that, you can forego the difficulties of the derived assignment operator by using the copy-swap idiom, which I would recommend, almost as much as I would just using std::string and making the whole issue disappear. - WhozCraig
@WhozCraig you are right about strncpy, it cannot terminate string, I forgot to put strlen(v) + 1. - Alex
In fact I used char only to give an example, of course that in my project I am not using char, but I have to allocate memory to others objects declared at the class. - Alex
No it can terminate a string, it simply won't if the source string length meets or exceeds the specified length parameter. The little -known fact is strncpy always fills N chars, where N is the length parameter, but won't terminate if the source is as long or longer than N before termination. If shorter, it tail-fills nulchars. Read more about it here and here. - WhozCraig

1 Answers

1
votes

What you're doing is a little awkward, but technically fine (except for leaking memory by not deleting name and value in the assignment operator before new[]-ing it), however only if you have no plans for multiple inheritance. That gets a bit messy, and may be why whatever books you're referring to are warning against it, but you shouldn't be using multiple inheritance (in general, but especially) on classes with data members anyways.

You might want to try a different approach regardless. Consider using a protected helper function (or a few) in the base class to set its variables:

class A
{
public:

// ...

private:
  char *value;

protected:
  void set_value(const char *str)
  {
    delete[] value; // remember, deleting null does nothing
    value = new char[strlen(str)+1];
    strncpy(value, str, strlen(str)); // Also, why do you need strncpy?
    // You'll get no null-terminator, which leads to major problems
    // Consider just strcpy(value, str);
  }
};

This way, you can set that value from any derived class, the functionality is still hidden from public use, and you don't have to write an assignment operator or copy constructor for an abstract class. Which, when you think about it, really doesn't make much sense, does it?

It also saves you from this:

A *a = new B;

B *b = new B;
(*a) = (*b); // ...with an assignment operator on A, this should compile.