copy constructor of a vector-derived class - c++

I have the following classes.
class CA {
...
};
class CB: public vector<CA> {
...
};
How shall I implement the copy constructor of CB? i.e.,
CB(CB& cb).
How do I copy the content of the vector of cb in?

Ignoring the issue with publicly inheriting from an std::vector, if you really need a copy constructor for your derived type (for instance, if you are managing dynamically allocated resources), then you can use the constructor initialization list, as in this example, where Foo takes the place of your std::vector in the inheritance hierarchy:
#include <iostream>
struct Foo
{
Foo() {}
Foo(const Foo&) { std::cout << "Copy Foo\n";}
};
struct Bar : public Foo
{
Bar() {}
Bar(const Bar& b) : Foo(b) {}
};
int main()
{
Bar b1;
Bar b2(b1);
}

Related

Copy Constructors of classes instantiating derived classes

I have unsuccessfully been trying to create a copy constructor of a class that instantiates a derived class.
Let's say I have the following pure virtual class:
class AbstractBar{
public:
virtual void printMe() = 0;
};
Class Bar inherits from AbstractBar as follows:
class Bar: public AbstractBar {
std::string name_;
public:
explicit Bar(std::string name) : name_ {std::move(name)}{};
void printMe() override { std::cout << name_ << std::endl; }
};
My class Foo now attempts to make use of polymorphism by declaring a pointer to type AbstractClass as follows:
class Foo{
std::unique_ptr<AbstractBar> theBar_;
public:
explicit Foo(std::unique_ptr<Bar> bar){
theBar_ = std::move(bar);
};
void printBar(){
theBar_->printMe();
}
};
I do however want Foo to be copied so I add the following copy constructor:
Foo(const Foo &other) {
theBar_ = std::unique_ptr<AbstractBar>();
*theBar_ = *(other.theBar_);
}
And this is where it breaks.
What I gather is that this may be a problem since theBar in the copy constructor thinks it is pointing to an AbstractBar but when I try to copy the object it points to, in the next line, I actually give it a derived Bar class.
Is there a proper way to implement this copy constructor?
First off, std::unique_ptr<T> is indeed unique. Therefore you cannot expect two things to point to the same instance-of-whatever by copying them. That said, I think what you're trying to do is clone whatever the "thing" is that is held by that member unique_ptr to allow a deep copy of a Foo.
If that is the case, you need a covariant clone. See below:
#include <iostream>
#include <string>
#include <memory>
struct AbstractBar
{
virtual ~AbstractBar() = default;
virtual std::unique_ptr<AbstractBar> clone() = 0;
virtual void printMe() = 0;
};
class Bar : public AbstractBar
{
std::string name_;
public:
explicit Bar(std::string name) : name_{std::move(name)} {};
std::unique_ptr<AbstractBar> clone() override
{
return std::make_unique<Bar>(name_);
}
void printMe() override
{
std::cout << name_ << std::endl;
}
};
class Foo
{
std::unique_ptr<AbstractBar> theBar_;
public:
explicit Foo(std::unique_ptr<Bar> bar)
: theBar_(std::move(bar))
{
}
Foo(const Foo &other)
: theBar_(other.theBar_->clone())
{
}
void printBar()
{
theBar_->printMe();
}
};
int main()
{
Foo foo(std::make_unique<Bar>("Some String"));
Foo bar(foo);
foo.printBar();
bar.printBar();
}
Important: foo and bar will each have their own Bar instance via a unique pointer to the abstract base of Bar, namely AbstractBar. Hopefully that was the intent. This isn't the only way to do this, but it is probably the easiest to understand.

Constructor - Copying Const Reference VS Moving Copied Value

I couldn't find the answer so I'm asking it here. What's the difference between THIS:
class Foo
{
public:
Foo(std::string string)
: m_String(std::move(string)) {}
private:
std::string m_String;
}
And THAT:
class Bar
{
public:
Bar(const std::string& string)
: m_String(string) {}
private:
std::string m_String;
}
I know that using a constructor from Bar copies data exactly from the value, but I don't really know what exactly happens when calling the Foo constructor.
Is there a difference in using constructor from Foo or Bar?
Don't use strings but a type where you can observe copying and moving:
#include <iostream>
struct test {
test() { std::cout << "constructor\n"; }
test(const test&) { std::cout << "copy\n";}
test(test&&) { std::cout << "move\n"; }
};
class Foo {
public:
Foo(test t) : t(std::move(t)) {}
private:
test t;
};
class Bar {
public:
Bar(const test& t) : t(t) {}
private:
test t;
};
int main() {
test t1;
Foo f{t1};
std::cout << "...........\n";
test t2;
Bar b{t2};
}
Output:
constructor
copy
move
...........
constructor
copy
Calling Foos constructor copies t1 to the constructors parameter, because it is taken by value and then the member is move constructed from the parameter.
Calling Bars constructor takes a reference (no copy, no move) and uses that to copy construct the member.
If the intention was to avoid the copying, you would provide a constructor that takes a test&&:
struct Baz {
Baz(test&& t) : t(std::move(t)) {}
test t;
};
Then Baz z(test{}); will construct a test and the member will be move constructed from that temporary. No copies involved.

Idiomatic way to prevent slicing?

Sometimes it can be an annoyance that c++ defaults to allow slicing. For example
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
foo y = x; // <- I dont want this to compile!
}
This compiles and runs as expected! Though, what if I dont want to enable slicing?
What is the idiomatic way to write foo such that one cannot slice instances of any derived class?
I'm not sure if there is a named idiom for it but you can add a deleted function to the overload set that is a better match then the base classes slicing operations. If you change foo to
struct foo
{
int a;
foo() = default; // you have to add this because of the template constructor
template<typename T>
foo(const T&) = delete; // error trying to copy anything but a foo
template<typename T>
foo& operator=(const T&) = delete; // error assigning anything else but a foo
};
then you can only ever copy construct or copy assign a foo to foo. Any other type will pick the function template and you'll get an error about using a deleted function. This does mean that your class, and the classes that use it can no longer be an aggregate though. Since the members that are added are templates, they are not considered copy constructors or copy assignment operators so you'll get the default copy and move constructors and assignment operators.
Since 2011, the idiomatic way has been to use auto:
#include <iostream>
struct foo { int a; };
struct bar : foo { int b; };
int main() {
bar x{1,2};
auto y = x; // <- y is a bar
}
If you wish to actively prevent slicing, there are a number of ways:
Usually the most preferable way, unless you specifically need inheritance (you often don't) is to use encapsulation:
#include <iostream>
struct foo { int a; };
struct bar
{
bar(int a, int b)
: foo_(a)
, b(b)
{}
int b;
int get_a() const { return foo_.a; }
private:
foo foo_;
};
int main() {
bar x{1,2};
// foo y = x; // <- does not compile
}
Another more specialised way might be to alter the permissions around copy operators:
#include <iostream>
struct foo {
int a;
protected:
foo(foo const&) = default;
foo(foo&&) = default;
foo& operator=(foo const&) = default;
foo& operator=(foo&&) = default;
};
struct bar : foo
{
bar(int a, int b)
: foo{a}, b{b}
{}
int b;
};
int main() {
auto x = bar (1,2);
// foo y = x; // <- does not compile
}
You can prevent the base from being copied outside of member functions of derived classes and the base itself by declaring the copy constructor protected:
struct foo {
// ...
protected:
foo(foo&) = default;
};

Provide default value for constructor initializing reference instance variable

I have a class Foo that has a reference to Bar as an instance variable. Is there a way to have one of the Foo constructors create a Bar instance (so users of the Foo class need not explicitly create a Bar object themselves)?
I'd like to do something like this:
class Foo {
private:
int size;
Bar& bar; // shared by other objects
//several other instance variables
public:
Foo(int s, Bar& b) : size(s), bar(b) {}
// This, of course, doesn't work. I can't think of an
// alternative that doesn't require users of Foo to
// create Bar
Foo(int s) : size(s), bar(Bar(s)) {}
}
(In "real life", Foo and Bar are more complicated. Bar is a friend of Foo that has a private constructor used only by Foo. Each Bar can be shared by several Foos. This isn't a major problem, I'm just curious if it can be done without pointers.)
The simplest solution would be to allocate a Bar if and when you need one. Adding a member std::unique_ptr<Bar> is the easiest way of achieving this. I can't conceive of a system that addresses your problem that will not add some memory overhead to your class. You either have to account for storage for a Bar even when it isn't needed or you have to account for some state to track rather or not your Bar is internally managed. Using a unique_ptr adds the size of a pointer to your class.
#include <memory>
class Foo {
private:
std::unique_ptr<Bar> storage;
Bar& bar;
int size;
public:
Foo(int s, Bar& b) : bar(b), size(s) {}
Foo(int s) : storage(std::make_unique<Bar>(s)), bar(*storage), size(s) {}
};
A more elaborate solution could be to provide a wrapper for Bar that provides a default constructor that takes care of initializing a new instance.
Note that in your example, you do not initialize the member in the same order as they are declared. Members will be initialized in the order they are declared regardless of how you order them in your initialization list.
If every Foo shall have it's own individual Bar-object (not a single shared one), then you could try the following:
class Foo {
private:
Bar& bar; // shared by other objects
int size;
Bar* defaultBar;
//several other instance variables
public:
Foo(int s, Bar& b) : size(s), bar(b), defaultBar(nullptr) {}
Foo(int s) : Foo(s, *(new Bar(14))) { defaultBar=&bar; };
virtual ~Foo() {
if (defaultBar)
delete defaultBar;
}
void setBar(Bar &b) {
if (defaultBar)
delete defaultBar;
defaultBar = nullptr;
bar=b;
}
};
Hope it is what you are looking for.
// This, of course, doesn't work. I can't think of an
// alternative that doesn't require users of Foo to
// create Bar
Foo(int s) : size(s), bar(Bar(14)) {}
You can use a default Bar object, which can be a static member variable of Foo or any other class that can provide such an object.
E.g.
class Foo {
private:
Bar& bar; // shared by other objects
int size;
//several other instance variables
static Bar& getDefaultBar();
public:
Foo(int s, Bar& b) : size(s), bar(b) {}
Foo(int s) : size(s), bar(getDefaultBar()) {}
}
Bar& Foo::getDefaultBar()
{
static Bar b(24);
return b;
}

copy constructor is implicitly deleted because the default definition would be ill-formed

I've got a class A (from a library over which I have no control) with a private copy constructor and a clone method, and a class B derived from A. I would like to implement clone for B as well.
The naive approach
#include <memory>
class A { // I have no control here
public:
A(int a) {};
std::shared_ptr<A>
clone() const
{
return std::shared_ptr<A>(new A(*this));
}
private:
A(const A & a) {};
};
class B: public A {
public:
B(int data, int extraData):
A(data),
extraData_(extraData)
{
}
std::shared_ptr<B>
clone() const
{
return std::shared_ptr<B>(new B(*this));
}
private:
int extraData_;
};
int main() {
A a(1);
}
however, fails, since the copy constructor of A is private:
main.cpp: In member function ‘std::shared_ptr<B> B::clone() const’:
main.cpp:27:42: error: use of deleted function ‘B::B(const B&)’
return std::shared_ptr<B>(new B(*this));
^
main.cpp:17:7: note: ‘B::B(const B&)’ is implicitly deleted because the default definition would be ill-formed:
class B: public A {
^
main.cpp:14:5: error: ‘A::A(const A&)’ is private
A(const A & a) {};
^
main.cpp:17:7: error: within this context
class B: public A {
There might a way to make use of A::clone() for B::clone(), but I'm not sure how this would work exactly. Any hints?
I presume it's a typo that your B has no public members at all,
and that you're missing a public: before the definition of B::B(int,int).
The author of the class represented by your A apparently wants it to be
cloneable but not copy constructible. That would suggest he or she wants all
instances to live on the heap. But contrariwise, there's the public
constructor A::A(int). Are you sure you are right about that?
It's plausible to suppose that the class can reveal enough information
about a given instance to constitute another instance. E.g., putting
a little more flesh on A:
class A {
public:
A(int a)
: data_(a){};
std::shared_ptr<A>
clone() const
{
return std::shared_ptr<A>(new A(*this));
}
int data() const {
return data_;
}
private:
A(const A & a) {};
int data_;
};
And if that is true, then the public constructor would render it merely
inconvenient to circumvent the private, undefined copy constructor:
A a0(1);
A a1{a0.data()}; // Inconvenient copy construction
So I'm less than confident that A faithfully represents the problem
class. Taking it at face value, however, the question you need to answer
is: Can you even inconveniently copy construct an A?
If not then you're stuck. If so, then you can use inconvenient copy
construction of A to expressly define a conventional copy constructor for B,
which is all you need. E.g.
class B: public A {
public:
B(B const & other)
: A(other.data()),extraData_(other.extraData_){}
B(int data, int extraData):
A(data),
extraData_(extraData)
{
}
std::shared_ptr<B>
clone() const
{
return std::shared_ptr<B>(new B(*this));
}
int extradata() const {
return extraData_;
}
private:
int extraData_;
};
#include <iostream>
int main()
{
B b(1,2);
std::shared_ptr<B> pb = b.clone();
std::cout << pb->data() << std::endl;
std::cout << pb->extradata() << std::endl;
return 0;
}
You need to make the copy-constructor of A protected so that the derived class could use it:
protected:
A(const A & a) { /*...*/ }
Hope that helps.
The reason the default definition of B's copy constructor is ill-formed is because - if it was permitted - it would invoke the private (therefore inaccessible to B) and not defined copy constructor of A.
Make A's copy constructor either protected or public, so it is accessible to B. Another (really bad) option is to declare class B as a friend of A. All possibilities would also require you to provide a definition for A's copy constructor.