Why will C++ copy constructor fail? - c++

#include <iostream>
#include <string>
using namespace std;
class A
{
public:
A() { i=1; j=2;};
A (A &obj) { i= obj.i+100; j= obj.j+100;};
int i;
int j;
};
class B:public A
{
public:
B():A() {i=10; j=20; k=30;};
B(A &obj) { A::A(obj); k=10000; };//
int k;
};
int main()
{
A dog;
B mouse(dog);
cout<<mouse.i<<endl;
cout<<mouse.k<<endl;
return 0;
}
I try to write a copy constructor for the derived class that takes advantage of the copy constructor for the base class. I expect that mouse.i should be 101, but in fact the compiling result is 1. The value for mouse.k is 10000, which is expected. I was wondering what's wrong with my code.

In this constructor:
B(A &obj) { A::A(obj); k=10000; };
A::A(obj); does not initialise the base sub-object; instead, it creates a local object also called obj. It's equivalent to A::A obj;, which is equivalant to A obj;. [UPDATE: or possibly it does something else, or possibly it's ill-formed - in any event, it's wrong.]
You want to use an initialiser list:
B(A & obj) : A(obj), k(10000) {}
Also, you almost certainly want the constructor parameters to be A const &, to allow construction from constant objects or temporaries.

You must use the initialization list to call the parent's constructor (and you should do it for all other members also):
B(A const& obj) : A(obj), k(10000) {}
Additionally, when copying you do not modify the original object, so you should take a const reference to it. That will allow you to copy from constant objects (or through constant references), improving const-correctness.

You should initialize the base class like this:
B(A &obj):A(obj) { k=10000; }
(more on this at What are the rules for calling the superclass constructor?). And a side-note: use const for copy constructor arguments:
A (const A &obj) {...}
EDIT:
The preferred way to initialize instance members is through an initialization list, so your ctor will look like
B(A &obj):A(obj), k(10000) { }

#include <iostream>
#include <string>
using namespace std;
class A
{
public:
A()
{
i=1;
j=2;
}
A (A &obj)
{
i= obj.i+100;
j= obj.j+100;
}
int i;
int j;
};
class B:public A
{
public:
B():A() {i=10; j=20; k=30;}
B(A &obj)
:A(obj)
{
//A::A(obj);
k=10000;
}//
int k;
};
int main()
{
A dog;
B mouse(dog);
cout<<mouse.i<<endl;
cout<<mouse.k<<endl;
return 0;
}
This work for me
B(A &obj)
{
A::A(obj)
}
Is illegal on gcc compiler

Related

How to handle objects that dont have a default constructor but are constructed in another constructor?

I have the following sample code
class ClassB {
public:
ClassB(int i); // No default constructor
}
class ClassA {
ClassB obj; //NOT a pointer
public
ClassA() {
//calculate someInt;
obj = ClassB(someInt); // doesnt work
}
}
How do I initialize obj?
The compiler complains about no appropriate default constructor available for obj
The best design solution for you would be to initialize member obj in the initialization list like this:
ClassA() : obj(someInt) { }
However, another option for you would be to declare the default constructor for ClassB like this:
ClassB() {}
or simply let the compiler create the one for you by using this:
ClassB() = default;
From C++ Standard this is:
defaulted default constructor: the compiler will define the implicit
default constructor even if other constructors are present.
If you go for a second option, then the following code would pass without the error:
#include <iostream>
class ClassB {
public:
ClassB() = default;
ClassB(int i);
};
class ClassA {
ClassB obj;
public:
ClassA() {
int someInt = 0;
obj = ClassB(someInt);
}
};
int main() {
return 0;
}
Check it out live
Conclusion
I would deeply recommend using the first option, the one with the initialization list because it is not needed to default construct objects before and then assigning to them. Also, this is the only option for objects that don't have an assignment operator.
UPDATE 1
One more way around this problem is using the std::shared_ptr<ClassB> obj in your ClassA as follows:
#include <iostream>
#include <memory>
class ClassB {
public:
ClassB(int i);
};
class ClassA {
std::shared_ptr<ClassB> obj;
public:
ClassA() {
int someInt = 0;
obj = std::make_shared<ClassB>(someInt);
}
};
int main() {
return 0;
}
UPDATE 2
One more possibility that came up to my mind is to calculate integer in a separate function and the just call it as part of the initialization list like in the following code:
#include <iostream>
class ClassB {
public:
ClassB(int i);
};
class ClassA {
ClassB obj;
public:
ClassA()
: obj(calculate())
{}
private:
int calculate() {
return 1;
}
};
int main() {
return 0;
}
Check it out live
You initialize members in the constructor initialization list. Like so:
ClassA() : obj(someInt) { }

Access private data member of class from unrelated class in C++ converter constructor

In the code given below, to access private data member of B we can use member function of class B and return the data member, assign that to the data member of A within the constructor (converter function). But I am unable to do so. Please suggest some help. Other way can be making Class A friend of B but there is need for accessing by constructor.
#include <iostream>
using namespace std;
class B
{
int i_;
public:
B(int i = 3) : i_(i) {}
int give() { return i_; }
};
class A
{
int i_;
public:
A(int i = 0) : i_(i) { cout << "A::A(i)\n"; }
A(const B &b1) : i_(b1.i_) {} // Type casting using constructor
int display() { cout << i_; }
};
int main()
{
A a;
B b; // object is constructed
a = static_cast<A>(b); // B::operator A(), converting data member of class B to class A
a.display();
return 0;
}
It's not enough to follow #StoryTeller's advice, you also need to change constructor of A to use proper 'getter' method so that you stop accessing private member:
A(const B &b1) : i_(b1.give()) {}
Your problem is const correctness. int give() is a non-const member function, which can only be called on non-const objects. However const B &b1 is a reference to a const object.
Since you don't modify the B object when returning the value of the integer, make your code const correct by const qualifying the member function:
int give() const { return i_; }
And now the A c'tor isn't attempting an illegal operation.

How to use a copy constructor with a base class?

I'm confused about base classes and copy constructors.
Say I have a class
class A {
public:
A(int m) : m(m) { return; }
virtual ~A() { return; }
int m;
}
And a class that inherits this
class B : public A {
public:
B(int n, int m) : A(m), n(n) { return; }
vitual ~B() { return; }
int n;
}
When I copy class B, how do I ensure that the m value in class A is copied as well?
The default copy constructor will copy all of the member variables, no matter whether they reside in the base class or a derived class.
If you create your own copy constructor for class B you will need to copy the class A members yourself, or better yet use the copy constructor for class A in the initializer list.
class B : public A {
public:
// ...
B(const B & b) : A(b), n(b.n) {}
// ...
};
The base copy constructor will be called before the derived copy constructor automatically. It's the same as for a regular constructor. (More accurately, the base constructor is called by derived initialization list before derived constructor continues). In your case, the default copy constructors are sufficient.
Be careful, however, that you do not copy a B into an A (search object splicing).
This code is your code just copy constructors are added with a class:
#include <iostream>
using namespace std;
struct Int
{
Int ()
{
}
Int(const Int&)
{
cout<< "Int copied" "\n";
}
};
class A
{
Int m;
public:
A(Int m) : m(m)
{
}
virtual ~A()
{
}
};
class B : public A
{
Int n;
public:
B(Int n, Int m) : A(m), n(n)
{
}
virtual ~B()
{
}
};
void f(B)
{
}
int main()
{
Int m,n;
B b(m,n);
cout<< "\n" "start:" "\n";
f(b);
cout<< "end";
}
Ubuntu Qt Creator Output says both are copied.
One can think there's a hidden member with type B in A and this hidden member can be initialized or copied as a usual member as in the above program with:
B(Int n, Int m) : A(m), n(n)
You should not return from a constructor/destructor, not even void.

C++ Constructors vs Initialization Lists speed comparison

Are there any differences in execution time between constructors and initialization lists?(or is it just a matter of coding preference).
I have a set of objects that needs to be created frequently and would like to know if there is any performance gain by using initialization lists instead of constructors.
If I were to create a million instances of class A and another million of class B which choice would be better(the objects represent packets generated within a network hence these numbers).
class A {
private:
int a, b;
public:
A(int a_var, int b_var):a(a_var), b(b_var) {};
};
class B {
private:
int a, b;
public:
B(int a_var, int b_var) {
a = a_var;
b = b_var;
}
};
If any of the constructors is faster than the other for primitive types(as in the example) will it be faster if a and b were to be replaced by types?
Type example:
class AType {
private:
string a, b;
public:
AType(string a_var, string b_var):a(a_var), b(b_var) {};
};
The difference is for types with no trivial default constructor, which is called for you by compiler in your class B. Your class B is equivalent to:
class B {
private:
SleepyInt a, b;
public:
// takes at least 20s
B(int a_var, int b_var) : a(), b()
// ^^^^^^^^^^
{
a = a_var;
b = b_var;
}
};
If you do not place member variable or base class constructor in initialization list - ithe default constructor is called for them. int is basic type - its default constructor costs nothing - so no difference in your example, but for more complex types constructor+assignment might cost more than just constructing.
Some funny example, just to illustrate the difference:
class SleepyInt {
public:
SleepyInt () {
std::this_thread::sleep_for(std::chrono::milliseconds( 10000 ));
}
SleepyInt (int i) {}
SleepyInt & operator = (int i) { return *this; }
};
class A {
private:
SleepyInt a, b;
public:
A(int a_var, int b_var):a(a_var), b(b_var) {};
};
class B {
private:
SleepyInt a, b;
public:
// takes at least 20s
B(int a_var, int b_var) {
a = a_var;
b = b_var;
}
};
It is commonly accepted practice to use initialization lists as opposed to assignment in a constructor, and there's a very good reason for that.
Initialization lists can be used to initialize both POD (Plain Old Data) and user-defined types. When initializing a POD type, the effect is exactly the same as an assignment operator, meaning there is no performance difference between initialization lists or assignment in a constructor for POD types.
When we consider non-POD types things get more interesting. Before the constructor is called, constructors for the parent class and then any contained members are invoked, and by default the no-argument constructor is called. Using an initialization list you are able to choose which constructor is called.
So to answer the question, there is a performance difference, but only when initializing non-POD types.
If members are of more or less complex types, then the assignment initialization will first cause the default constructor call and then operator=, which may take longer.
There won't be a performance improvement if the types are built-in/intrinsic type.
That said:
Conclusion: All other things being equal, your code will run faster if
you use initialization lists rather than assignment.
Initialization list is benefical reference types, member class objects, or const members. Otherwise it takes more time.
Look at my test code:
#include <iostream>
#include <ctime>
using namespace std;
class A{
int a;
public:
A(int a_):a(a_){}
};
class B{
int b;
public:
B(){
}
B(int b_){
b=b_;
}
};
class C{
B b;
public:
C(int c_):b(c_){
}
};
class D{
B b;
public:
D(int d_){
b=d_;
}
};
int main()
{
clock_t start1[10], start2[10], end1[10], end2[10];
for(int j=0;j<10;j++){
start1[j]=clock();
for(int i=0;i<100000;i++){
A *newA=new A(i);
delete newA;
}
end1[j]=clock();
start2[j]=clock();
for(int i=0;i<100000;i++){
B *newB=new B(i);
delete newB;
}
end2[j]=clock();
}
double avg1=0, avg2=0;
for(int i=0;i<10;i++){
avg1+=(end1[i]-start1[i]);
avg2+=(end2[i]-start2[i]);
}
cout << avg1/avg2 << endl;
for(int j=0;j<10;j++){
start1[j]=clock();
for(int i=0;i<100000;i++){
C *newC=new C(i);
delete newC;
}
end1[j]=clock();
start2[j]=clock();
for(int i=0;i<100000;i++){
D *newD=new D(i);
delete newD;
}
end2[j]=clock();
}
avg1=avg2=0;
for(int i=0;i<10;i++){
avg1+=(end1[i]-start1[i]);
avg2+=(end2[i]-start2[i]);
}
cout << avg1/avg2 << endl;
system("pause");
return 0;
}
Example outputs like this:
1.02391
0.934741

passing 'const Class2' as 'this' argument of 'int Class1::get_data()' discards qualifiers

I'm trying to set up a copy constructor and i'm getting this error
class Class1{
public:
int get_data();
void set_data(int);
private:
int d;
};
int Class1::get_data(){
return d;
}
void Class1::set_data(int data){
d = data;
}
class Class2 : public Class1{
Class2(const Class2&);
};
Class2::Class2(const Class2 &c2) : Class1(){
set_data(c2.set_data());
}
whats a solution to this problem. i read some of the previous questions and i understand why this is happening. but making set_data() const is not an option.
whats the accepted approach for copy constructors?
thanks,
You could just write a constructor for Class1 taking an int parameter:
class Class1 {
explicit Class1 (int i) : d (i) {}
// as before
};
class Class2 : public Class1 {
Class2 (Class2 const & c2) : Class1 (c2.get_data ()) {}
};
However, the default copy constructor should be enought here (i.e. you don't need to write your own, the compiler will do it for you).
Generally speaking, you should use initialisation lists:
http://www.parashift.com/c++-faq-lite/ctors.html
in the constructors (read the whole entry in the faq)
Edit: You forgot the 'const' qualifier for your get_data function.
Don't you want:
set_data(c2.get_data());
(and make the Class1::get_data() member function const)?
But you really should be using constructor initialization lists:
Class2::Class2(const Class2 &c2)
: Class1(c2)
{
}
This code uses the compiler-generated default copy constructor for Class1. In many cases you shouldn't use the default copy constructor or copy-assign operator overload, but here it's fine because the sole data member of Class1 is an int object.
In fact, you could even rely on the compiler-generated default copy constructor for Class2.
EDIT: Here is some example code:
#include <iostream>
class Class1{
public:
Class1() : d(0) { } // Provide a no-arg constructor to initialize `d`
int get_data() const; // Class1::get_data() is `const` because it does not change the `Class1` object.
void set_data(int);
private:
int d;
};
int Class1::get_data() const{
return d;
}
void Class1::set_data(int data){
d = data;
}
class Class2 : public Class1{
public:
Class2();
};
Class2::Class2()
: Class1()
{
}
int main() {
Class2 other_c2;
other_c2.set_data(14);
Class2 c2(other_c2);
std::cout << c2.get_data() << '\n';
}
http://codepad.org/jlplTYrH