The Human class turned out to be non-copied, since it contains a field of type unique_ptr, for which the copy constructor and the copying assignment operator have been removed. This prevents the compiler from automatically generating a copy constructor and assignment operator for the Human class.
How can I implement a copy constructor and a copy assignment operator in the Human class? A copy of the human must own a copy of the cat, if the original human owned it.
struct Cat {
Cat(const string& name, int age)
: name_(name)
, age_(age) //
{
}
const string& GetName() const noexcept {
return name_;
}
int GetAge() const noexcept {
return age_;
}
~Cat() {
}
void Speak() const {
cout << "Meow!"s << endl;
}
private:
string name_;
int age_;
};
unique_ptr<Cat> CreateCat(const string& name) {
return make_unique<Cat>(name, 2);
}
class Human {
public:
explicit Human(const string& name)
: name_(name) {
}
const string& GetName() const noexcept {
return name_;
}
void SetCat(unique_ptr<Cat>&& cat) noexcept {
cat_ = std::move(cat);
}
unique_ptr<Cat> ReleaseCat() noexcept {
return std::move(cat_);
}
private:
string name_;
unique_ptr<Cat> cat_;
};
Your copy constructor might look like
Human::Human(const Human& rhs) :
name_(rhs.name_),
cat_(rhs.cat_ ? std::make_unique<Cat>(*rhs.cat_) : std::nullptr)
{}
but getting rid of std::unique_ptr and having Cat by value (or std::optional<Cat>) would be simpler:
Human::Human(const Human&) = default;
If Cat is polymorphic, a clone method would be required:
Human::Human(const Human& rhs) :
name_(rhs.name_),
animal_(rhs.animal_ ? rhs.animal_->clone() : std::nullptr)
{}
Related
I am having some trouble with an unexpected output in the following simple code. The output works fine with the base class but I run into trouble with the derived class for some reason.
#include <iostream>
#include <string>
using namespace std;
class vehicle {
public:
string* name;
vehicle() {}
vehicle(const string& inputName) {name = new string(inputName);} //constructor
virtual ~vehicle() {delete name; name = nullptr;} // always make base class destructor virtual
//vehicle(const vehicle& rhs) {*this = rhs; cout << "copy called" << endl;} //copy constructor
vehicle& operator=(const vehicle& rhs) {
cout << "assignment called" << endl;
if(this == &rhs){
return *this;
}
name = new string(*rhs.name);
return *this;
} //assignment operator
virtual string& getName() const {return *name; cout << "base" << endl;} //mark function const if we are not going to make any changes to the object
};
class car : public vehicle {
string *title = new string;
public:
car() : vehicle() {}
car(const string& inputName) : vehicle(inputName) {*title = inputName;}
virtual ~car() {}
virtual string& getName() const {string temp = *title; return temp; cout << "derived" << endl;}
};
int main() {
car test("honda");
string temp;
temp = test.getName();
cout << temp;
return 0;
}
I am intending to get the following output:
honda
But am getting:
~weird square boxes~
Edit:
What i'm really trying to accomplish is something like the following in the derived class:
virtual string& getName() const {return "Car: " + *name;}
Before I get enflamed for using the heap for the string, please know that I am only experimenting here. It is my understanding that this should, in theory, work.
This function
virtual string& getName() const {string temp = *title; return temp; cout << "derived" << endl;}
invokes undefined behavior because it returns a reference to a local object temp that will not be alive after exiting the function.
You could define the function like
virtual const string& getName() const {return *name;}
and
const string& getName() const override { return *title;}
And the statements after return statements do not have an effect.
Also other your code has drawbacks. For example the copy assignment operator produces a memory leak.
Or you need explicitly to define the destructor for the class car.
Pay attention to that there is no sense to declare data members name and title as pointers to objects of the type std::string. Instead declare data members of the type std::string.
I got a template class Atlas that will store objects of Animal class and derived classes of Animal;
here's the code:
#include <iostream>
#include <assert.h>
#include <list>
using namespace std;
class Animal {
protected:
std::string m_name;
Animal (std::string name): m_name {name} {}
public:
virtual std::string regn() const { return "???"; }
virtual ~Animal(){
cout << "Destructor animal"<<'\n';}
};
class Nevertebrate : public Animal{
public:
virtual std::string regn() const { return "nevertebrate";}
virtual ~Nevertebrate();
};
class Vertebrate: public Animal {
protected:
/* std::string m_name;
Vertebrate (std::string name)
:m_name {name} {} */
Vertebrate (std::string name)
: Animal {name} {}
public:
virtual std::string regn() const { return "vertebrate";}
virtual ~Vertebrate(){
cout<<"Destructor vertebrate"<<'\n';};
};
class bird: public Vertebrate {
public:
bird(std::string name)
: Vertebrate{ name }{}
void set_name (std::string nume){
m_name = nume;}
std::string get_name(){
return m_name;}
virtual std::string regn() const {return "pasare";}
virtual ~bird (){
cout << "destructor bird"<<'\n';}
};
template <class T>
class Atlas
{
private:
int m_length{};
T* m_data{};
public:
void SetLength(int j);
Atlas(int length)
{
assert(length > 0);
m_data = new T[length]{};
m_length = length;
}
Atlas(const Atlas&) = delete;
Atlas& operator=(const Atlas&) = delete;
~Atlas()
{
delete[] m_data;
}
void erase()
{
delete[] m_data;
m_data = nullptr;
m_length = 0;
}
T& operator[](int index)
{
assert(index >= 0 && index < m_length);
return m_data[index];
}
int getLength() const;
};
template <class T>
int Atlas<T>::getLength() const
{
return m_length;
}
template <class T>
void Atlas<T>::SetLength(int j){m_length = j;
}
int main()
{
Atlas<Bird> AtlasBird(10);
Bird b;
AtlasBird.SetLength(11);
AtlasBird[10] = b --- it gets a memoryleak from here.
return 0;
}
I want to overload the += operator so that i can insert a new object into my Atlas, (e.g. AtlasAnimal).
I tried with the SetLength function to increase the length, (e.g. AtlasAnimal.SetLength(11)) but when i try to assign AtlasAnimal[10] an object (e.g. Bird b) it drops a memory leak.
I'm sorry if there was a similar question answered, but i couldn't find anything that helps
I have a base class Animal and a derived class Bird : Animal. I use a template class that will store vectors of pointers to either Animal or Bird objects. I want to overload the += operator in such a way that I can insert a new animal right in the Atlas, so m_length = m_length + 1, pages.push_back(animal), just to get the idea.
Here's my template class:
template <class T>
class Atlas2 {
public:
int m_length;
std::list<T> pages;
Atlas2() { m_length = 0; }
~Atlas2() {}
void adauga(T data);
T operator+=(const T& data) {
this->m_length++;
this->pages.push_back(data);
return *this;
};
};
And here's the Animal/Bird classes:
class Animal {
protected:
std::string m_name;
public:
Animal() {}
Animal(std::string name) : m_name{name} {}
virtual void set_name(std::string name) { m_name = name; }
virtual std::string get_name() { return m_name; }
virtual std::string regn() const { return "???"; }
virtual ~Animal() { cout << "Destructor animal" << '\n'; }
};
class Bird : public Animal {
public:
bird() : animal() {}
bird(std::string name) : Animal{name} {}
void set_name(std::string nume) { m_name = nume; }
std::string get_name() { return m_name; }
std::string regn() const override { return "pasare"; }
~bird() { cout << "destructor pasare" << '\n'; }
};
However, I can't figure this out. When I use the overloaded += operator in main() like this:
Pasare *c = new Pasare{"vulture"};
Atlas2<Animal *> Atlas;
Atlas += c;
It shows me an error, that it couldn't convert Atlas<Animal *> to <Animal*>.
How should I implement this correctly? Any tip?
Note: The template works fine, I can store in my list pointers to either Animal or Birds without problems, and access their specific methods. I just can't figure out the += part.
You should return Atlas2<T> & not T:
Atlas2<T>& operator+=(const T& data) {
this->m_length++;
this->pagini.push_back(data);
return *this;
};
The basic problem is that you've declared your operator+= as returning a T, but the return statement in it is return *this;, which is an Atlas2<T>.
If you change the return type to Atlas2<T> &, it should work. That's what you would normally want to return from an operator+= anyways, though with your use, it doesn't matter much as you're ignoring the returned value.
How can I copy all the objects to another set of objects. I created a temporary object so I can add the current "robot" to the "robotSquad". I am trying to dynamically add it
I am new to the concept of operator overloading, I might have the wrong assumption on what I'm doing. Im using the += operator, making a temp if there is no space in "robotSquad" adding it to temp then copying it to the original robotSquad named r_robot.
I could possibly be doing all this wrong, need help Thanks!
RobotSquad& RobotSquad::operator+=(const Robot& p_robot) {
if (count <= sizeof(r_robots)) {
//how do i copy?
RobotSquad temp[count+1];
temp[count]=p_robot;
for(int i=0 ;i<=sizeof(r_robots);i++){
temp[i]=r_robots[i];
}
} else {
this ->r_robots[count]=p_robot;
}
count++;
return *this;
}
class RobotSquad {
char* name ;
Robot *r_robots;
int count;
public:
//constructor
RobotSquad();
RobotSquad(Robot* , int, char* p_name= "No name");
~RobotSquad();
//getters
char* getName();
Robot* getRoster();
int getCount();
//setters
char setName();
Robot setRobot();
int setCount();
//other
RobotSquad& operator+=(const Robot&);
private:
void setEmpty();
};
With std, it could be:
class RobotSquad {
std::vector<Robot> robots;
std::string name;
public:
//constructor
RobotSquad() = default;
explicit RobotSquad(const std::vector<Robot>& robots,
const std::string& name= "No name")
: robots{robots}, name{name}
{}
~RobotSquad() = default;
RobotSquad& operator+=(const Robot& robot)
{
robots.push_back(robot);
return *this;
}
// ...
};
I'm trying to create a named-arguments-like constructor for some of the classes of a project.
The way I'm doing it is by defining a class proxy which will hold the arguments and pass an instance of this proxy to the constructor of my classes.
Everything worked fine until I had to derive one of my classes.
Basically I thought: I'm gonna derive the new derived class proxy from the base class proxy. This works too, but only if I use only the derived proxy class arguments.
Here is an example since it is easier to understand:
class Person
{
public:
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
PersonArgs& Name(const std::string& name)
{
_name = name;
return *this;
}
const std::string& Surname() const { return _surname; }
PersonArgs& Surname(const std::string& surname)
{
_surname = surname;
return *this;
}
protected:
std::string _name;
std::string _surname;
}
public:
Person()
: _name("")
, _surname("")
{ }
Person(const PersonArgs& args)
: _name(args.Name())
, _surname(args.Surname())
{ }
protected:
std::string _name;
std::string _surname;
}
class PersonEx : public Person
{
public:
class PersonExArgs : public Person::PersonArgs
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
protected:
std::string _address;
}
public:
PersonEx()
: _address("")
{ }
PersonEx(const PersonExArgs& args)
: Person(args)
, _address(args.Address())
{ }
protected:
std::string _address;
}
int main(int argc, char** argv)
{
// This is ok since PersonExArgs::Address returns a PersonExArgs&
PersonEx* p1 = new PersonEx(PersonEx::PersonExArgs().Address("example"));
// This won't work since PersonExArgs::Name returns a PersonArgs&
PersonEx* p2 = new PersonEx(PersonEx::PersonExArgs().Address("example").Name("Mark"));
}
Basically, since I chain the arguments returning a reference to the proxy class instance when I set an argument, it breaks when using this from a derived proxy class since it will return a reference to the base proxy class and not the derived one, not allowing me to access the derived proxy arguments and neither pass it to the constructor of the derived class.
Anyone has an idea on how to fix this?
Maybe covariant return types are what you are looking for.
See here for more details.
You can define PersonArgs as (note virtual keywords placed around):
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
virtual PersonArgs& Name(const std::string& name)
{
_name = name;
return *this;
}
const std::string& Surname() const { return _surname; }
virtual PersonArgs& Surname(const std::string& surname)
{
_surname = surname;
return *this;
}
protected:
std::string _name;
std::string _surname;
};
Then define PersonExArgs as (note override and the covariant return type):
class PersonExArgs : public Person::PersonArgs
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
PersonExArgs& Name(const std::string& name) override
{
PersonArgs::Name(name);
return *this;
}
PersonExArgs& Surname(const std::string& surname) override
{
PersonArgs::Surname(surname);
return *this;
}
protected:
std::string _address;
};
Probably it's annoying for you have to override each and every function in the base class but it does the work nicely.
See it up and running on wandbox.
The most common solution to this problem is the Curiously Recurring Template Pattern (CRTP):
template <typename Derived>
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
Derived& Name(const std::string& name)
{
_name = name;
return static_cast<Derived&>(*this);
}
const std::string& Surname() const { return _surname; }
Derived& Surname(const std::string& surname)
{
_surname = surname;
return static_cast<Derived&>(*this);
}
protected:
std::string _name;
std::string _surname;
};
...
class PersonExArgs : public Person::PersonArgs<PersonExArgs>
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
protected:
std::string _address;
};
In your case, you could combine it with another base class to clean up the interface:
class Person {
class PersonArgsBase
{
public:
const std::string& Name() const { return _name; }
const std::string& Surname() const { return _surname; }
protected:
std::string _name;
std::string _surname;
};
template <typename Derived>
class PersonArgs : public PersonArgsBase
{
Derived& Name(const std::string& name)
{
_name = name;
return static_cast<Derived&>(*this);
}
Derived& Surname(const std::string& surname)
{
_surname = surname;
return static_cast<Derived&>(*this);
}
};
...
};
class PersonEx {
class PersonExArgs : public Person::PersonArgs<PersonExArgs>
{
...
};
};