5

if I have a class with attributes like this:

struct MyClass {
   double **arowofpointers;
   int capacity;
};

Now, if the task says "make sure this line of code in the main function is legal:

MyClass a(10); //makes a variable whose type is MyClass that has the capacity of 10

But make sure that the following line of code in the main function is not legal:

MyClass a=10;

Still, the following line of your code in the main function should be legal:

a=b+c;

where, a,b and c are all variables whose type is MyClass.

Which constructors should I make? Is there anything I should set on delete or something?

Tas
  • 7,023
  • 3
  • 36
  • 51
Sanjichy
  • 67
  • 2
  • 1
    Aren't all your question really the point of the assignment? Write the expressions in your main, and modify the class until all the constraints hold. Go over your course material, and read how one can define constructors with certain properties. – StoryTeller - Unslander Monica Sep 20 '18 at 10:38
  • 1
    "Which constructors should I make? " Explicit ones. – Quimby Sep 20 '18 at 10:39
  • 4
    You probably want an [explicit](https://en.cppreference.com/w/cpp/language/explicit) constructor to disable the second line and operator overloading will get you the third. – Arnav Borborah Sep 20 '18 at 10:39
  • The task is too complicated, I reduced its formulation and wrotet his question, I only have problems with assignment and initialization. 'MyClass a(10)' should be legal while ' MyClass a=10' shouldn't. – Sanjichy Sep 20 '18 at 10:40
  • 1
    Use the explicit keyword in front of your 1-argument constructor – Alberto Miola Sep 20 '18 at 10:41
  • @Sanjichy Here is a [minimal working example](https://coliru.stacked-crooked.com/a/2768271bfb920e77) similar to your requirements that I quickly wrote that should work. – Arnav Borborah Sep 20 '18 at 10:44

2 Answers2

13

Constructing an instance of type MyClass like this

MyClass a(10);

requires a constructor that takes an integer parameter:

class MyClass {
  public:
    MyClass(int param);

  // ...
};

But as constructors are implicit by default (which is unfortunate), allowing for MyClass a = 10;, you need to make it explicit:

// This constructor must be called explicitly via MyClass(int)
explicit MyClass(int param);

This will make the compiler complain when it encounters MyClass a = 10;.

For the operator part of your question, you might want to have a look at this (the "Arithmetic Operators" part).

lubgr
  • 37,368
  • 3
  • 66
  • 117
1

MyClass a(10); requires a conversion constructor that takes an integer as input. To prevent MyClass a=10;, make this constructor explicit.

a = b + c; requires an operator+ to concatenate two MyClass objects, and an operator= to assign one MyClass object to another. If you want to support initializations like MyClass a = b;, MyClass a = b + c;, etc, you will also need a copy constructor as well.

And don't forget a destructor.

So, you will need these constructors and operators in your struct:

struct MyClass
{
private:
   double **arowofpointers;
   int capacity;

public:
   // default constructor
   MyClass();

   // conversion constructor
   explicit MyClass(int cap);

   // copy constructor
   MyClass(const MyClass &src);

   // move constructor (C++11 and later only, optional but recommended)
   MyClass(MyClass &&src);

   // destructor
   ~MyClass();

   // copy assignment operator
   MyClass& operator=(const MyClass &rhs);

   // move assignment operator(C++11 and later only, optional but recommended)
   MyClass& operator=(MyClass &&rhs);

   // concatenation operator overload
   MyClass operator+(const MyClass &rhs) const;

   // compound concatenation assignment operator (optional)
   MyClass& operator+=(const MyClass &rhs);

   // swap helper
   void swap(MyClass &other);
};

// std::swap() overload
void swap(MyClass &lhs, MyClass &rhs);

Where the implementations might look something like this:

#include <algorithm>

MyClass::MyClass()
    : arowofpointers(nullptr), capacity(0)
{
}

MyClass::MyClass(int cap)
    : arowofpointers(new double*[cap]), capacity(cap)
{
    std::fill_n(arowofpointers, capacity, nullptr);
}

MyClass::MyClass(const MyClass &src)
    : arowofpointers(new double*[src.capacity]), capacity(src.capacity)
{
    std::copy(src.arowofpointers, src.arowofpointers + capacity, arowofpointers);
}

MyClass::MyClass(MyClass &&src)
    : arowofpointers(nullptr), capacity(0)
{
    src.swap(*this);
}

MyClass::~MyClass()
{
    delete[] arowofpointers;
}

MyClass& MyClass::operator=(const MyClass &rhs)
{
    if (&rhs != this)
        MyClass(rhs).swap(*this);
    return *this;
}

MyClass& MyClass::operator=(MyClass &&rhs)
{
    MyClass tmp(std::move(*this));
    rhs.swap(*this);
    return *this;
}

MyClass MyClass::operator+(const MyClass &rhs) const
{
    MyClass tmp(capacity + rhs.capacity);
    std::copy(arowofpointers, arowofpointers + capacity, tmp.arowofpointers);
    std::copy(rhs.arowofpointers, rhs.arowofpointers + rhs.capacity, tmp.arowofpointers + capacity);
    return tmp;
}

MyClass& MyClass::operator+=(const MyClass &rhs)
{
    MyClass tmp = *this + rhs;
    tmp.swap(*this);
    return *this;
}

void swap(MyClass &lhs, MyClass &rhs)
{
    lhs.swap(rhs);
}

That being said, if you use std::vector instead, then you don't need to handle most of this yourself, let the compiler and STL to the heavy work for you:

#include <vector>

struct MyClass
{
private:
   std::vector<double*> arowofpointers;

public:
   MyClass();
   explicit MyClass(int cap);

   MyClass operator+(const MyClass &rhs) const;

   MyClass& operator+=(const MyClass &rhs);

   void swap(MyClass &other);
};

void swap(MyClass &lhs, MyClass &rhs);

#include <algorithm>

MyClass::MyClass()
    : arowofpointers()
{
}

MyClass::MyClass(int cap)
    : arowofpointers(cap, nullptr)
{
}

MyClass MyClass::operator+(const MyClass &rhs) const
{
    MyClass tmp(arowofpointers.capacity() + rhs.arowofpointers.capacity());
    tmp.arowofpointers.insert(tmp.arowofpointers.end(), arowofpointers.begin(), arowofpointers.end();
    tmp.arowofpointers.insert(tmp.arowofpointers.end(), rhs.arowofpointers.begin(), rhs.arowofpointers.end();
    return tmp;
}

MyClass& MyClass::operator+=(const MyClass &rhs)
{
    MyClass tmp = *this + rhs;
    tmp.swap(*this);
    return *this;
}

void swap(MyClass &lhs, MyClass &rhs)
{
    lhs.swap(rhs);
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770