So, I have a Base class, and two Derived classes, let's call them Deriv1 and Deriv2.
Let's say Base class has lots of (protected or public) variables, which of course then are also included in Deriv1 and Deriv2.
Now let's say I have an instance of Deriv1. The billions of variables from the Base class are filled with individual values. Now I want to create a Deriv2 instance, using these shared values.
Now my question: How to copy over the Base class part of Deriv1 to Deriv2 without writing an assigment operator where I'd have to manually list all of the billions of Base class variables (and update it everytime I change something in the Base class)? Is there some way, be it dirty or not, to do this?
My initial idea was:
Deriv1 drv1;
... // actions regarding drv1, like changing variables
Base tempbase = drv1; // slicing off the non-base parts of Deriv1
Deriv2 drv2 = *dynamic_cast<Deriv2*>(&tempbase); // downcast
This did not work. It did compile (I had to add a virtual dummy function to Base for it), but during runtime, it said "access violation", so I guess dynamic_cast returned a null pointer. I tried using a reference instead pointer in the dynamic_cast, which also didn't work.
You could make use of the (implicitly defined) copy constructor of the base class, which copies all members (even private ones) by value (i.e. shallow copy). You could define an explicit copy constructor for the base class as well, but it seems not to be necessary in your case.
See the following example:
class A {
public:
A (int x, int y) : x(x), y(y) { };
// implicitly defined: A (const A &anA) : x(anA.x), y(anA.y) { }
private:
int x, y;
};
class B : public A {
public:
int z;
B(const A&anA) : A(anA) { }
B(const B&b, int z) : A(b), z(z) { }
};
class C : public A {
public:
int anythingElse;
C(const A&anA) : A(anA) { }
};
int main()
{
A a(10,20); // a.x = 10; a.y = 20
B b1(a); // b1.x = 10, b1.y = 20, b1.z = undefined.
B b2(b1,30); // b2.x = 10, b2.y = 20, b2.z = 30.
C c(b1); // c.x = 10; c.y = 20; c.anythingElse = undefined
return 0;
}
use of static_cast instead of dynamic_cast will solve this.
Related
I've been programming C++ for decades and never expected this limitation.
Is there something obvious I'm overlooking? I guess I need to make the X() constructor take an argument for i and let that constructor initialize it? What can the point of this weird limitation possibly be? I can understand forbidding us from initializing an object twice, but it's not initialized at all! (Or, I guess in the absence of an explicit constructor, X's constructor will give it a default initialization?) And yet:
class X {
public:
X() {};
int i;
};
class X1 : public X {
public:
X1() : i(1){};
};
results in error:
initial.cpp: In constructor 'X1::X1()':
initial.cpp:11:10: error: class 'X1' does not have any field named 'i'
X1() : i(1){};
^
That's meant to be as initialization of object is a part of that objects creation, you either have to provide initialization via X, or redesign to be able initialize it directly:
class X {
public:
X() {};
X(int _i) : i(_i) {};
int i;
};
or
class X {
public:
int i;
};
so you can do this:
class X1 : public X {
public:
X1() : X{1}{};
};
Allowing what you tried to do would imply that we had to insert a new initialization behavior into existing sequence, which could be compiled already as part of different compilation unit or to allow that member be initialized twice. Former is problematic to implement with whole concept of C++ implementation as native compilers, the latter makes sequence of initialization non-linear and contradicting existing ideology.
Note, that usually composition is preferable to inheritance if you target storage area instead of behaviour, i.e.
InterfaceX {
// declarations to be used in descendants
};
class X1 : public InterfaceX
{
X m_x;
public:
X1() : m_x{1} {};
};
If we actually require polymorphic use, we'd use InterfaceX for virtual methods. And if we would need to "cut down" X1 to X, there need to be an conversion operator operator X () {return m_x; }
I am not an advanced programmer. Suppose there is a classic diamond inheritance:
class Base
class A: virtual public Base
class B: virtual public Base
class Last: public A, public B
Suppose Base has a variable, m_x, that is common to both A and B, such that only one of A, or B, can be called at a time, not both (which is what is needed). To get around this, this is used:
class Last: public A, public B
{
private:
std::unique_ptr<Base> m_p;
public:
Last(int i)
{
if (i)
m_p = std::unique_ptr<Base>(new A());
else
m_p = std::unique_ptr<Base>(new B());
}
};
This is fine, but now m_p->m_x cannot be accessed anymore because it says it's protected, but both A and B call m_x in their constructors directly, with no problems.
Is this a known limitation or is this the wrong way to do it? If it's wrong, what solutions are there?
Here is some code based on the diagram found here (a bit lower on the page):
#include <iostream>
#include <memory>
class Power
{
protected:
double m_x;
public:
Power() {}
Power(double x): m_x {x} {}
virtual ~Power() = default;
};
class Scanner: virtual public Power
{
public:
Scanner() {}
Scanner(double x): Power(x) {} // scan document
};
class Printer: virtual public Power
{
public:
Printer() {}
Printer(double x): Power(x) {} // print document
};
class Copier: public Scanner, public Printer
{
private:
std::unique_ptr<Power> m_p;
public:
Copier() {}
Copier(double x, int i)
{
if (i)
m_p = std::unique_ptr<Power>(new Scanner(x));
else
m_p = std::unique_ptr<Power>(new Printer(x));
}
void print() { std::cout << this->Power::m_x << '\n'; }
};
int main(int argc, char *argv[])
{
Copier *copier {new Copier(1.618, 0)};
copier->print();
copier = new Copier(3.14, 1);
copier->print();
return 0;
}
Using both this->m_p and this->Power::m_x (according to answers and comments) compiles, but the output is 0.
To be sure I spell it out all: not only I am quite a beginner, but, given the example above, it oesn't really have to stay that way if there is another alternative to call Scanner or Printer only one at a time from inside Copier. I am not asking for opinions, I understand it's forbidden, but I won't reject them coming from more experienced users. After all, I am learning.
Both virtual inheritance and std::unique_ptr are red herrings. The problem comes down to this:
class Base
{
protected:
int m_x;
};
class Last : public Base
{
public:
Last()
{
Base base;
base.m_x = 0; // error
m_x = 1; // no error
}
};
The error is something like error C2248: 'Base::m_x': cannot access protected member declared in class 'Base' or error: 'int Base::m_x' is protected within this context.
The explanation is that protected is a somewhat special case. It does not only work on class level but also on the object level. And you have two relevant objects here:
The Last object which is being created by the constructor, i.e. the one pointed to by this. It's also a Base object because of the is-a inheritance relationship.
The local object named base within the constructor.
Now, the problem is that in the line base.m_x = 0;, you are in the context of the first object and not the second one. In other words, you are trying to access the m_x of base from outside base. C++ simply does not allow this.
A very technical explanation can be found in the C++ standard at §11.4 [class.protected], a more easily understandable one in an excellent answer here on Stack Overflow.
protected doesn't mean quite what you think it does.
Although Last is derived from Base, member functions of Last don't have access to the protected members of any Base object - just those Base objects that are sub-objects of some Last object.
So you can write: this->Base::x because *this is a Last object, but not m_p->x, because *m_p is of static type Base.
As others have noted, I think this is actually an XY problem. Having an object which derives from two classes, and then also has a pointer to another object of one of those classes is very strange indeed. I think you need to clarify what you are trying to do.
I have a base_class which has no default constructor, and I'd like to define a vector version of it (called derived_class). I know I should initialize the base_class constructor in my derived_class constructor, but the code below which attempts to initialize a vector with size dim and base_class(0,1) in each row cannot be compiled (it complains error: constructor for 'derived_class' must explicitly initialize the base class 'base_class' which does not have a default constructor), unless I add a default constructor (the commented line) to base_class. Do I miss or misunderstand something? Is there a way to make it work without defining the default base_class constructor?
#include <iostream>
#include <vector>
class base_class
{
public:
//base_class(){};
base_class(double a, double b){a_=a; b_=b;}
private:
double a_, b_;
};
class derived_class : public base_class
{
public:
derived_class(int dim): vector_object(dim, base_class(0,1)){};
std::vector<base_class> print_vector_object() {return vector_object;}
private:
std::vector<base_class> vector_object;
};
int main()
{
int dim = 3;
derived_class abc(3);
std::cout << abc.print_vector_object().size() << std::endl;
return 0;
}
UPDATE: I understand that I can totally avoid inheritance here in this simple case, but please assume that I do need inheritance for actual practice, thanks.
UPDATE2: As hinted by #vishal, if the constructor of derived_class is written as
derived_class(int dim) : base_class(0,0), vector_object(dim, base_class(0,1)) {};
The code can pass compiler. But I still don't understand why I have to initialize in this way...
Well, since you do not want to create default constructor in base class, you can call base constructor by:
derived_class(double a, double b, int dim) : base_class(a,b), vector_object(dim, base_class(0,1)) {};
Your vector_object is a red herring and has nothing to do with the problem, as you can verify with the following piece of code which will also make the compiler complain about the missing base_class default constructor:
class derived_class : public base_class
{
public:
derived_class(int dim) {} // error, tries to use `base_class` default constructor,
// but there is none...
};
You must either provide a default constructor or use a non-default one. In every instance of derived_class, there is a base_class sub-object, and the sub-object has to be created somehow.
One possible source of misunderstanding is the fact that objects in an inheritance hierarchy are initialized from top to bottom (base to derived). It may not seem logical at first sight, but by the time the derived_class constructor runs, the base_class sub-object must already exist. If the compiler cannot provide for this, then you get an error.
So even though the derived_class constructor specifies how the base_class sub-object is created, the actual creation of the sub-object happens before the creation of the derived_class part.
You are asking the following:
shouldn't the base_class object be initialized in my code?
Your code must initialize it, but it does not. You don't initialize it anywhere, and the default initialization does not work because the base class does not have a default constructor.
Sometimes, it helps to consider inheritance a special form of composition (there are indeed some striking similarities). The following piece of code suffers from the same problem as the one in your posting:
class base_class
{
public:
//base_class(){};
base_class(double a, double b){a_=a; b_=b;}
private:
double a_, b_;
};
class derived_class // <--- no inheritance
{
public:
base_class my_base; // <--- member variable
derived_class(int dim) {};
};
Would you still think that derived_class initializes the base_class object?
Another possible source of misunderstanding is the aforementioned red herring. You are saying:
I just don't understand why I cannot initialize it in a vector (...).
Because the vector member variable has nothing to do with the base_class sub-object, or with the public base_class member variable in my other example. There is no magical relationship between a vector member variable and anything else.
Taking your original piece of code again, a complete derived_class object can be pictured as follows in memory:
+-------------------+
| +---------------+ |
| | double | | <--- `base_class` sub-object
| | double | |
| +---------------+ |
+-------------------+ +--------+--------+--------+....
| std::vector ---------------> | double | double | double |
+-------------------+ | double | double | double |
+--------+--------+--------+....
^
|
|
a lot of other
`base_class` objects
The base_class objects managed by the vector are completely unrelated to the base_class sub-object that owes its existence to class inheritance.
(The diagram is a little over-simplified, because a std::vector normally also stores some internal book-keeping data, but that's irrelevant to this discussion.)
However, your code does not make a convincing case for inheritance anyway. So why do you inherit in the first place? You may as well do like this:
#include <iostream>
#include <vector>
class base_class
{
public:
//base_class(){};
base_class(double a, double b){a_=a; b_=b;}
private:
double a_, b_;
};
class derived_class // <--- no more inheritance (and thus wrong class name)
{
public:
derived_class(int dim) : vector_object(dim, base_class(0,1)){};
std::vector<base_class> print_vector_object() {return vector_object;}
private:
std::vector<base_class> vector_object;
};
int main()
{
int dim = 3;
derived_class abc(3);
std::cout << abc.print_vector_object().size() << std::endl;
return 0;
}
Are you sure, that a derived_class-object is a base_class-object and holds a vector of base_class-objects?
I assume, you actually only want a vector of base_class-objects. If that is true, don't derive derived_class from base_class. Actually that is where your compiler message comes from. It tells you, that you'll have to initialize the base_class aspect of your derived_class-object.
So here is my solution for you (beware, code is untested and will probably contain some bugs):
#include <iostream>
#include <vector>
class base_class
{
public:
// c++11 allows you to explicitly delete the default constructor.
base_class() = delete;
base_class(double a, double b):
a_{a}, b_{b} // <- prefer initializers over constructor body
{};
private:
double a_;
double b_;
};
class derived_class // <- this name is wrong now of course; change it.
{
public:
derived_class(int dim):
// better initialize doubles with float syntax, not int.
vector_object{dim, base_class{0.0, 1.0}}
{};
// Note: this will copy the whole vector on return.
// are you sure, that is what you really want?
auto print_vector_object() -> std::vector<base_class> {
return vector_object;
};
private:
std::vector<base_class> vector_object;
};
int main(int, char**)
{
// int dim = 3; <- this is useless, you never use dim.
auto abc = derived_class{3};
std::cout << abc.print_vector_object().size() << std::endl;
return 0;
}
Note: my code is meant to be C++11.
I have rewritten your class slightly
#include <iostream>
#include <vector>
class base_class {
private:
double a_, b_;
public:
//base_class(){};
base_class(double a, double b ) : a_(a), b_(b) {}
virtual ~base_class();
};
class derived_class : public base_class {
private:
std::vector<base_class> vector_object;
public:
explicit derived_class( int dim ) : base_class( 0, 1 ) {
vector_object.push_back( static_cast<base_class>( *this ) );
}
~derived_class();
std::vector<base_class> get_vector_object() const { return vector_object; }
};
int main() {
int dim = 3;
derived_class abc(3);
std::cout << abc.get_vector_object().size() << std::endl;
return 0;
}
This builds and compiles correctly. There were a few changes I made: I used the constructors member initializer list where applicable, I've added a virtual destructor to your base class; any time you inherit from a base class should have a virtual destructor, I moved all private member variables to the top of the class instead of at the bottom, I prefixed the derived_class constructor with the explicit keyword since you only have 1 parameter passed into it, I've changed the derived_class constructor to use the base_class constructor within its member's initialization list and I populated its member variable vector within the constructor using the push_back() method and statically casting the dereferenced this pointer to a base_class type, and I've also changed your print_vector_object method to just get_vector_object since it doesn't print anything and only return the member vector from the class. I also declared this method as const so that it doesn't change the class since you are only retrieving it. The only question that I have is what does the int parameter in the derived_class do? It is not used in any place and you have no member variable to store it.
This section of your derived class here
public:
derived_class(int dim): vector_object(dim, base_class(0,1)){};
where you declare your constructor is not making any sense to me.
It appears that you are trying to use the member initialization list to populate your vector member variable by passing in your derived class's passed in parameter and calling the constructor to your base class with values of {0,1}. This will not work as you would expect. You first have to construct your Base Class object which is a sub object to this derived class than within your constructor's function scope you can then populate your member vector.
What you have will cause a problem because you do not have a default constructor supplied that is available to try and construct your derived type. Since from what I can gather on what you have shown and what it appears what you are trying to do it seems that you want to have the base_class initialized to {0,1} when the derived constructor is called; if this is the case you can just call your implemented constructor for the base_class with {0,1} passed in its constructor while your derived type tries to be constructed. This will allow the derived_class to be constructed properly since the base_class has been constructed. Now that you are able to begin construction of your derived type it looks like you want to save the constructed base_class into your derived types vector member variable. This is why I do this within the constructor and not within the initialization list and I push_back an instance of the derived type that is statically casted back to a base type using the dereferenced this pointer. Also when I set a break point in the main function where you are trying to print its size and I look at derived_class's member variable it is populated with 1 object that has the values of a = 0 and b = 1. To be able to print these you would have to add public get methods to return each variable. Also if the int parameter in your derived class is not needed you can remove it along with the explicit keyword. You could also implement a second constructor for the derived type that takes in two doubles just as the base does and pass those parameters from the derived_class constructor to the base_class constructor like this:
public:
derived_class( double a, double b ) : base_class( a, b ) {
vector_object.push_back( static_cast<base_class>( *this ) );
}
I will demonstrate a simple example of a base and two derived classes where the first instance will have to set the values upon construction while the second will have to use its own constructor where there is no default constructor that is defined in the base class.
class Base {
private:
double x_, y_, z_;
public:
Base( double x, double y, double z );
virtual ~Base();
};
Base::Base() :
x_( x ), y_( x ), z_( z ) {
}
Base::~Base() {
}
class DerivedA : public Base {
private:
int value_;
public:
explicit DerivedA( int value );
~DerivedA();
};
// In This Case A Must Set The Values In The Constructor Itself: I'll Just
// Set Them To (0, 0, 0) To Keep It Simple
DerivedA::DerivedA( int value ) :
Base( 0, 0, 0 ),
value_( value ) {
}
DerivedA::~DerivedA() {
}
class DerivedB : public Base {
private:
int value_;
public:
DerivedB( int value, double x, double y, double z );
~DerivedB();
};
// In This Case B Doesn't Have To Know What Is Needed To Construct Base
// Since Its Constructor Expects Values From Its Caller And They Can
// Be Passed Off To The Base Class Constructor
DerivedB::DerivedB( int value, double x, double y, double z ) :
Base( x, y, z ),
value_( value ) {
}
DerivedB::~DerivedB() {
}
Let me know if this helps you out!
Suppose I have three classes:
typedef struct base
{
float A;
float B;
...
base() : A(1.0f), B(1.0f) {}
} base;
class derived1 : base
{
int C;
int D;
};
class derived2 : base
{
int E;
int F;
};
And I would like to copy base class data from one derived class object to another.
Is it safe to do the following, to only copy the base class values of A, B, etc... from one object to another?
derived1* object1 = new derived1;
derived2* object2 = new derived2;
void make_object1()
{
object1->C = 2;
object1->D = 3;
}
void make_object2()
}
object2->A = 4;
object2->B = 5;
object2->E = 6;
object2->F = 7;
}
void transfer_base()
{
*((base*)object1) = *((base*)object2);
}
Assuming my program would need to do this sort of operation often would there be a better (faster code) way to accomplish this?
The reason that I'd doing this is I have written a simulation and a graphical renderer. I want to update graphical display objects with only select data from objects in the simulation as efficiently as possible. The simulation is extremely CPU intensive...
So far this approach seems to be working however I'm concerned there may be something I'm overlooking...
The code
*((base*)object1) = *((base*)object2);
is quite unsafe, because the C style casts can do just about anything. Such as reinterpretation, or casting away constness.
Instead, if you want to invoke base::operator=, then invoke that explicitly. Excplicit = good, implicit = bad.
I.e.,
object1->base::operator=( *object2 );
This is still not “safe”, because the slicing may break the class invariant of the derived class. And anyone trying to get a handle on what happens in this code may be surprised by the sudden change of values in the base class sub-objects, and waste a lot of time trying to ascertain where those values are coming from. But at least it’s not as bad as the C style casting.
Instead, why not create your own assignment method in the base class (removing the unneeded C-artifact typedeffing):
struct base
{
float A;
float B;
...
base() : A(1.0f), B(1.0f) {}
base& assign_base(const base& right) { A = right.A; B = right.B; }
};
Then you can just say
der1.assign_base(der2);
From an answer on Inheritance: why is there a difference in behaviour between inherited and supplied variables?, I understand that the below code prints 0 because there is only one copy of x.
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
class B : public A {
public:
B() { x = 0; }
};
int main() {
A* ab = new B;
cout << ab->x << endl; // prints 0
}
But does this not go against the very meaning of inheritance?
I coded class B to interit publicly from class A, and I expected it to inherit a copy of member variable x, which should have resulted in ab->x printing value 10.
What am I missing here? I am finding it too difficult to understand why this prints 0 despite inheritance.
Here is a simple figure that briefly explains inheritance in terms of member variables:
When the ChildClass is created, the BaseClass is created and exists inside the ChildClass. Variables a, b and c can be accessed from both ChildClass and Baseclass (depending on access modifiers such as public, private and protected). They're shared, not copied.
I expected it to inherit a copy of member variable x
No, you don't inherit by copying. B inheriting A results in every object of B containing a subobject of type A. Since x is defined in A, you modify the A subobject by assigning to x.
The following reformulation of the code makes this subobject visible:
#include <iostream>
using namespace std;
struct A {
int x;
A() { x = 10; }
};
struct B {
A subobject;
B(): subobject() { this->subobject.x = 0; }
};
int main() {
B* ab = new B;
cout << ab->subobject.x << endl; // prints 0
}
This is of course not identical to inheritance since the types A and B are now not related any more (you cannot convert from B to A), but it is somewhat analogous to what the compiler sees when you use inheritance.
inherit a copy of member variable x - well, it doesn't inherit a copy, it just inherits the variable. and it did.
First the constructor of A runs (x=10), the the constructor of B (x=0). After that, x is obviously 0.
Based on your comment, I think your looking for composition and not inheritance:
class B {
public:
A a;
int x;
};
B inherits x from A (with the value 10 set in A's constructor), but then immediately sets it to 0 in its own constuctor.
There is only one x shared by A and B.
Or to put it another way, there is no implicit 0-ness or 10-ness to the member x. What happens, happens because you call the constructor of B with the new call. Whether the x is defined in A or in B or as a global variable, doesn't matter. The constructor of B sets it to 0, so it is 0.
Does this help?