Reputation: 589
template<typename T = uint8_t> class ArrayRef {
using uint = unsigned int;
protected:
ArrayRef() {}
ArrayRef(const ArrayRef&) {}
ArrayRef& operator=(const ArrayRef& other) { return *this; }
};
class ByteArray : ArrayRef<uint8_t> {
ByteArray(const ArrayRef&);
ByteArray& operator=(const ArrayRef&);
public:
ByteArray() {}
};
class Base {
using uint = unsigned int;
protected:
Base() {}
Base(const Base&) {}
Base& operator=(const Base& other) { return *this; }
};
class Derived : Base {
Derived(const Derived&);
Derived& operator=(const Derived& other) { return *this; }
public:
Derived() {}
};
int main() {
ByteArray ba;
ByteArray ba2 = ba; // no error, why?
ba = ba2; // no error why?
Derived d;
Derived d2 = d; // error (expected) - Calling a private constructor
d = d2; // error (expected) - Calling private assignment operator
}
Two questions about the code above.
Upvotes: 3
Views: 258
Reputation: 117433
- Can you explain why the templated code behaves differently than the non-templated code? (see the comments in main().
The difference does not have anything to do with templates.
The difference is that your copy constructor and copy assignment operator are implicitly defined (as public
) in ByteArray
. In Derived
you've made them private
. If you take the template out of the question, it may be easier to see the difference between your two versions:
class ArrayRef {
protected:
ArrayRef() {}
ArrayRef(const ArrayRef&) {}
ArrayRef& operator=(const ArrayRef& other) { return *this; }
};
class ByteArray : ArrayRef {
ByteArray(const ArrayRef&); // your converting ctor
ByteArray& operator=(const ArrayRef&); // your converting assignment op
public:
ByteArray() {}
// copy contructor - implicitly defined:
// ByteArray(const ByteArray&) = default;
// copy assignment operator - implicitly defined:
// ByteArray& operator=(const ByteArray&) = default;
};
If you now try copying a ByteArray
it will work just as fine as when it was based on an instance of a class template. Compare the above ByteArray
with your Derived
in which you've actually made the copy constructor and copy assignment operator private
.
- How would I go about creating private copy constructors and assignment operators properly for templated code like this, in order to prevent object copies?
In order to prevent copies, you may delete
them:
class ByteArray : private ArrayRef<uint8_t> {
public:
ByteArray(const ByteArray&) = delete;
ByteArray& operator=(const ByteArray&) = delete;
ByteArray() {}
};
or make them private
to allow ByteArray
s and friend
s to make copies:
class ByteArray : private ArrayRef<uint8_t> {
private:
ByteArray(const ByteArray&) { ... }; // or `= default`
ByteArray& operator=(const ByteArray&) { ...; return *this; } // or `= default`
public:
ByteArray() {}
};
Note that the private
(converting) constructor and (converting) assignment operator that takes a const ArrayRef<uint8_t>&
as input does not prevent the implicitly defined copy constructor and copy assignment operator that takes a const ByteArray&
as input from behing created in ByteArray
.
In your Derived
class, you've actually made the copy constructor and copy assignment operator private
which is why you get the expected compilation errors when trying to use those.
Here's a full example that includes your (converting) constructor and assignment operator as well as a (user defined) copy constructor and copy assignment operator.
#include <cstdint>
#include <iostream>
template<typename T = uint8_t> class ArrayRef {
protected:
ArrayRef() {}
ArrayRef(const ArrayRef&) {}
ArrayRef& operator=(const ArrayRef& other) { return *this; }
};
class ByteArray : ArrayRef<uint8_t> {
ByteArray(const ArrayRef&) { std::cout << "your converting ctor\n"; }
ByteArray& operator=(const ArrayRef&) {
std::cout << "your converting assignment op\n"; return *this;
}
public:
ByteArray(const ByteArray&) { std::cout << "copy ctor\n"; }
ByteArray& operator=(const ByteArray&) {
std::cout << "copy assignment op\n"; return *this;
}
ByteArray() {}
};
int main() {
ByteArray a;
ByteArray b = a;
a = b;
}
You can see in the output that none of your private
methods are used:
copy ctor
copy assignment op
Upvotes: 2