I read that we can use in case member pointer to function or array.
How I can write copy constructor and copy assignment if I have member type pointer to function or pointer to array.
class test {
public:
test(const test& other) {
// code
}
test& operator=(const test& other) {
if (this != &other) {
// code
}
return *this;
}
private:
int (*fnc_ptr)(int, int);
int (*arr_ptr)[2];
};
Related
I am new to the topic of overloading copy constructors and I just wanted someone to look at my code for my class and see if I am overloading my copy constructor correctly. It is only using a single string as user input. Also, do I need the '&' or not?
class TODO {
private:
string entry;
public:
List* listArray = nullptr;
int itemCount = 0, currInvItem = 0;
int maxLength = 22;
TODO() { entry = ""; };
TODO(const string& ent) { setEntry(ent); }; // Is this correct?
void setEntry(string ent) { entry = ent; };
string getEntry() const { return entry; };
void greeting();
void programMenu();
void newArray();
void getList();
void incList();
void delTask();
string timeID();
string SystemDate();
friend istream& operator >>(istream& in, TODO& inv);
friend ostream& operator <<(ostream& out, TODO& inv);
void componentTest();
void setTask(string a);
string getTask();
bool validTask(string a);
bool notEmpty(string e);
};
That's correct, but it's just a constructor of TODO taking a const reference to a string. You can test it here.
Passing const string& ent (by const reference) is not a bad idea. Another option would be to pass string ent (by value), and move that string when initializing entry, i.e. : entry{ std::move(ent) }. As here.
The class TODO has a default copy constructor. Check the line at the Insight window here (you'll have to click Play first).:
// inline TODO(const TODO &) noexcept(false) = default;
The default copy constructor would just copy the members, including the List pointer, but not the List elements (shallow copy). Notice both instances of TODO would be pointing to the same List elements, and any operation on them would affect both instances.
Should you want to implement a custom copy constructor, the syntax would be (see here):
TODO(const TODO& other) {
std::cout << "custom copy_ctor\n";
*this = other;
// Copy listArray elements
...
}
This is in c++, using Visual Studio 2019 (haven't tried other compilers).
I want to add a templated operator= method. If the parameter is non-const, it works fine. But if the parameter is const, even if I make a version with a const parameter, it isn't called. Instead, it does a simple shallow copy.
If I use a named function instead of the operator, it works as expected. Similarly, if it's not templated, the operator is called as expected. The combo seems to be the issue.
Here's an example that exhibits the issue.
class CTest
{
public:
int x{};
CTest() = default;
CTest(int value) : x(value) {}
// non-const operator=
template<class SrcType>void operator=(SrcType& src)
{
x = src.x;
}
// const operator=
template<class SrcType>void operator=(const SrcType& src)
{
x = src.x;
}
};
int main()
{
CTest nonConstSrc{ 3 };
const CTest constSrc{ 5 };
CTest result;
result = nonConstSrc; // correctly calls non-const operator=
result = constSrc; // ? shallow copy, not calling const operator=
return 0;
}
Any ideas how to get it to use my overloaded function? Thanks.
Your const function template is not called because compiler generated default copy assignment operator by default, which has signature operator=(const CTest&). When compiler must choose between non-template function and template one (when both has the same match), the former is preferred. That is why your templated method is not called.
To help compiler to select version you want, add:
CTest& operator=(const volatile CTest&) = delete;
by above, you disable normal operator=, volatile here is imporant, without it compiler will complain that operator= is disabled. By adding volatile, you just make that template version is better matched than volatile one.
The rest is not changed:
template<class SrcType>
void operator=(SrcType& src)
{
x = src.x;
puts("boom1");
}
template<class SrcType>
void operator=(const SrcType& src) {
x = src.x;
puts("boom2");
}
Demo
If a class does not have a copy-assignment declared, the compiler will generate one implicitly.
You class does not have a copy-assignment operator, it only has a template assignment operator.
When called with a const object the implicitly declared assignment operator is a better match during overload resolution.
The issue here is that we can't delete the implicitly declared assignment operator, since it will then generate a compiler error. We can however write our own assignment operator that forwards to our template.
#include <iostream>
class CTest
{
public:
int x{};
CTest() = default;
CTest(int value) : x(value) {}
CTest(const CTest& v) = delete;
CTest& operator=(const CTest& v) {
return operator=<CTest>(v);
}
// non-const operator=
template<class SrcType>CTest& operator=(SrcType& src)
{
x = src.x;
std::cout << "non-const\n";
return *this;
}
template<class SrcType>CTest& operator=(const SrcType& src)
{
x = src.x;
std::cout << "const\n";
return *this;
}
};
int main()
{
CTest nonConstSrc{ 3 };
const CTest constSrc{ 5 };
CTest result;
result = nonConstSrc; // correctly calls non-const operator=
result = constSrc; // calls copy-assignment and forwards to template
return 0;
}
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?
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).
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);
}
I'm wondering if there is a way to implement copy constructors and assignment operators such that only a small modification is needed when these are redefined for a class.
For example, consider a class as such:
class Foo {
private:
int* mInt_ptr;
/* many other member variables
of different types that aren't
pointers */
public:
Foo();
Foo(const Foo&);
Foo& operator=(const Foo&);
~Foo();
};
Now, in order to deal with the pointer mInt_ptr I would need to handle it appropriately in the copy constructor and assignment operator. However, the rest of the member variables are safe to do a shallow copy of. Is there a way to do this automatically?
Once a class becomes large it may become tedious and unwieldy to explicitly write out the operations to copy the non-pointer member variables, so I'm wondering if there is a way to write, say, a copy constructor such as:
Foo::Foo(const Foo& tocopy)
{
mInt_ptr = new int(*tocopy.mInt_ptr);
/* Do shallow copy here somehow? */
}
rather than the explicit form of:
Foo::Foo(const Foo& tocopy)
{
mInt_ptr = new int(*tocopy.mInt_ptr);
mVar1 = tocopy.mVar1;
mVar2 = tocopy.mVar2;
...
...
mVarN = tocopy.mVarN;
}
Generally, don't use raw pointers, for exactly the reason that you're now fighting with. Instead, use a suitable smart pointer, and use copy-swap assignment:
class Foo
{
int a;
Zip z;
std::string name;
value_ptr<Bar> p;
public:
Foo(Foo const &) = default;
Foo & operator=(Foo rhs)
{
rhs.swap(*this);
return *this;
}
void swap(Foo & rhs)
{
using std::swap;
swap(a, rhs.a);
swap(z, rhs.z);
swap(name, rhs.name);
swap(p, rhs.p);
}
};
namespace std { template <> void swap<Foo>(Foo & a, Foo & b) { a.swap(b); } }
The value_ptr could be a full-blown implementation, or something simple such as this:
template <typename T> // suitable for small children,
class value_ptr // but not polymorphic base classes.
{
T * ptr;
public:
constexpr value_ptr() : ptr(nullptr) { }
value_ptr(T * p) noexcept : ptr(p) { }
value_ptr(value_ptr const & rhs) : ptr(::new T(*rhs.ptr)) { }
~value_ptr() { delete ptr; }
value_ptr & operator=(value_ptr rhs) { rhs.swap(*this); return *this; }
void swap(value_ptr & rhs) { std::swap(ptr, rhs.ptr); }
T & operator*() { return *ptr; }
T * operator->() { return ptr; }
};
How about you wrap all the shallow-copy bits in a small helper struct and use the default copy behaviour there.
class Foo {
private:
int* mInt_ptr;
struct helper_t
/* many other member variables
of different types that aren't
pointers */
} mHelper;
public:
Foo();
Foo(const Foo&);
Foo& operator=(const Foo&);
~Foo();
};
Foo::Foo(const Foo& tocopy)
{
mInt_ptr = new int(*tocopy.mInt_ptr);
mHelper = tocopy.mHelper;
}
Using better primitives, as Kerrek suggested, seems like better design though. This is just another possibility.
Regardless if you use raw pointers or smart pointers the Kerrek's solution is right in the sense that you should make a copy constructor, destructor and swap and implement assignment using those:
class Foo
{
private:
int* mInt_ptr;
// many other member variables
// of different types
public:
Foo()
: mInt_ptr(NULL)
// initialize all other members
{}
Foo(const Foo& that)
: mInt_ptr(new int(*that.mInt_ptr) )
// copy-construct all other members
{}
Foo& operator=(const Foo& that)
{
// you may check if(this == &that) here
Foo(that).swap(*this);
return *this;
}
~Foo()
{
delete mInt_ptr;
// and release other resources
}
void swap(Foo& that)
{
std::swap(mInt_ptr, that.mInt_ptr);
// swap all members
}
};
The members are inline here just to keep it compact, usually it is not advisable to burden class definition with inline member definitions.
I have an object constructor that takes in a const pointer to a const object
A::A( const B* const ex): m_B(B){};
where m_B:
const B* const m_B;
I am now trying to create a copy constructor and assignment operator
I have tried the following without any luck.
Copy Constructor:
A::A( const A& cpy): *m_B(*cpy.m_B) {}
This does not work...how do I approach this?
Assignment Operator:
A& A::operator=(const A& rhs) {
*m_B = *rhs.m_B // I know this won't work because const cannot be assigned
// error: assignment of read-only data-member
}
Any ideas how to solve this problem?
If you want deep copies anyways, why do you have a pointer? Just have a raw object.
class B{
// ...
};
class A{
const B _b;
public:
A(A const& other)
: _b(other._b) {}
private:
// no assignment operator, since const objects can't be reassigned
A& operator=(A const&); // undefined
};
Your problem is, constructors don't have the return value.
And assignment operator is operator=, not operator().
In your constructor, you took a pointer and saved pointer, not the contents of object the pointer points to. If you take this semantics, you should only copy pointers instead of copying the content: (Or do you have something else to achieve?)
class B;
class A {
public:
const B* m_b;
A( const B* const ex): m_B(ex){};
//copy constructor
A(const A& cpy): m_B(cpy.m_B){};
//assignment operator
A& operator=(const A&cpy) {m_B = cpy.m_B;};
};
The assignment operator might have to create a new instance with new:
A& A::operator=(const A& rhs) {
m_B = new B(rhs.m_B);
return *this;
}
Of course, you have to keep track of this, so you can delete the pointer if you allocate it. If you don't want to keep track, use new in the constructor as well.
Or even better, use the new shared_ptr to not have to care about pointers much at all.
The "placement new" operator can be useful when assigning objects that have const pointers.
class ref
{
public:
// Normal constructor creates new immutable reference.
ref(const char* const ptr, size_t len): m_ptr(ptr),m_len(len) {}
// Copy constructor creates new copy of existing immutable reference.
ref(const ref& o): m_ptr(o.m_ptr),m_len(o.m_len) {}
// Assignment operator replaces existing immutable reference with another one.
// Previous reference is gone.
ref& operator=(const ref& o) { new (this) ref(o.m_ptr, o.m_len); return *this; }
private:
const char* const m_ptr;
size_t m_len;
}