Coming from a Java/C# background and need a bit of help understanding what is happening here in C++...
class A {
int x;
public:
A(int x) : x(x){}
void f(int y) {
cout << x + y << endl;
}
};
class B : virtual A {
int x;
public:
B(int x) : A(2*x), x(x) {}
virtual void f(int y){
cout << x + 2*y << endl;
}
};
void h(){
B b(5);
A &a = dynamic_cast<A &>(b);
a.f(10);
b.f
}
void g() {
A *a = this;
a->f(10);
B *b = dynamic_cast<B *>(a);
b->f(10);
}
Calling h() is ok but calling g() will not work. Can someone explain why? Also, in the line A(int x) : x(x){} what does : x(x){} do? Same question for B(int x) : A(2*x), x(x) and : A(2*x), x(x).
Thanks so much in advance for your help.
A(int x) : x(x){} what does : x(x){} do?
: x(x) is the initializer list. The variable in the paranthesis is the argument received while the outer one is the member variable. It means member variable x is initialized with the value of the x argument received.
B(int x) : A(2*x)
Here you are calling the base class constructor( i.e, A) that receives an integer. x is the variable received by constructor B. This is a way of calling parameterized base class constructor from derived class constructor. By default, derived class constructor invokes the default base class constructor. In your case, if you don't provide the A(2*x) it fails because the base class has no default constructor.
g() is just a free function and not a member of a class, so this has no meaning. I'm not exactly sure what you're trying to do there
With regards to:
A(int x): x(x)
Your A class has int x as a member. This is calling the constructor of that integer with the x value that is passed into the constructor of A. In my opinion this is bad style and you should differentiate between the two. For example
class A {
int x;
public:
A(int x_in) : x(x_in){}
//...
};
This is equivalent to
class A {
int x;
public:
A(int x_in) {
x = x_in;
}
//...
};
1) As per MSDN (responding to your question related to g());
The this pointer is a pointer accessible only within the nonstatic member functions of a class, struct, or union type. It points to the object for which the member function is called. Static member functions do not have a this pointer.
2) The A(int y) : x(y) {} initializes A::x (the member before () with the value inside the "()" i.e. y (modified variable names for better understanding). Same is the case as with B(int x) : A(2*x), x(x) {}. It calls the base class's (A) constructor with the parameter 2*x and then initializes B::x with the value inside the (), i.e. x.
3) Also, g() wouldn't work because the dynamic_cast<> would throw a compile error since the object that's being casted needs to have at least 1 virtual function. If the only virtual function would be the destructor, then dynamic_cast<> would work.
g is a function at file-scope, aka it doesn't belong to any class. Because of this, you can't use this.
The : x(x)-style expressions are member constructors - they initialize (i.e. call the constructor on) the members of the class.
Related
Is it safe to call non-virtual base methods from member initializer list? And virtual?
It is not safe to call any member function (virtual or not virtual) before all base have been initialized. Bellow an example given in the standard ([class.base.init]§16):
class A {
public:
A(int);
};
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined behavior: calls member function but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined behavior: calls member function but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
};
There are more subtle cases.
As I was saying in the comment:
The first thing that is initialized in the initializer list of a derived class is the base class. Explicitly it looks like this:
class A{ ... };
class B : public A {
int x, y;
B() : A{}, x{...}, y{...} {
...
}
};
Therefore, when initiallizing x and y you can call any non virtual method of A, as it is already constructed.
The second part of the question doesn't have much to do with virtualness - It is simply a question of whether you can call a member function in the constructor. The answer is yes, but - you need to make sure you don't use any uninitialized parts of the object.
e.g.
struct Base {
virtual int f(int i) = 0;
};
struct Derived : public Base {
int x;
int y;
virtual int f(int i) override { return i; }
Derived(int i) : Base{}, x{f(i)}, y{f(x)} {}
};
is fine, but writing ... Derived(int i) : Base{}, x{f(y)}, y{f(i)} ... is not.
Class A contains the protected int x. Class B extends class A. Now what class B wants to do is set the value of x as a passing argument in its own constructor. When I try to do that, I get the error:
""x" is not a non-static data member or base class of class "B"".
#include <string>
#include <iostream>
class A {
protected:
int x;
public:
A()
{
}
};
class B : public A {
public:
B(int x)
: x(x)
{
}
};
int main()
{
}
You can "set" it, but not initialize it, because it has already been initialized when the base class object gets initialized. You can "set" it like this:
B(int x)
{
this->x = x; // assignment, not initialization
}
It would make more sense for one of A's constructors to take care of the initialization of A::x:
A(int x) : x(x) {}
and then use that in B:
using A::A; // allows B b{42};
I defined a Class, whose constructor consist of 3 integer arguments.
class A{
int a,b,c;
A(int x,int y,int z){
a=x;
b=y;
c=z;
}
};
Now, another class is defined as follows
class B{
A a;
B(A x){
a=x;
}
};
The error I am getting is
Error: no matching function for call to ‘A::A()’
Can somebody help me in defining these two classes ?
You are not implementing constructors correctly. You need to use a member initialization list:
class B {
A a_;
public:
B(const A& a) : a_(a) {}
};
otherwise the member a_ is going to be default constructed before the body of the constructor is entered. Your class A does not have a default constructor so this leads to an error.
This question already has an answer here:
Why is Default constructor called in virtual inheritance?
(1 answer)
Closed 9 years ago.
C++11 standard provides a way to inherit constructors from the base class. My question is regarding earlier standards. Suppose I inherit constructors in the following way:
class Base {
public:
Base() {};
Base(int b) { a = ++b;}
virtual int foo() {return 0;}
int a;
};
class A : public virtual Base {
public:
A() {}
A(int b): Base(b) {}
int foo() {return a*a;}
};
class C : public A {
public:
C() {}
C(int b ): A(b) {}
int foo() { return (a*a + a);}
};
Note that I am having virtual inheritance of the Base class. Now when I try to initialize a pointer to an object of type C then instead of calling Base(b) constructor, the code ends up calling Base() constructor. Here is the main function that I used:
int main(){
C *c = new C(5);
std::cout << c->Base::a << std::endl;
}
The output value of "a" is 0. However, when I remove the virtual keyword while inheriting the Base class, then Base(b) constructor is called and the value of "a" is 6. Can someone help me in understanding what is going on? Why is it that with virtual inheritance default constructor is called?
Virtual base classes are initialised based on the member initialiser list of the constructor of the most derived class.
In your case, when you're creating an instance of C, its Base subobject will be initialised based on the member-initialiser list in C's constructor; and since Base is not listed there, it will be default-initialised.
If you were creating an instance of A, then indeed A's member-initialiser list would be used.
So to call the Base constructor which you want, you'd have to modify C's constructor like this:
C(int b ): A(b), Base(b) {}
I get a compile error, which I'm slightly confused about. This is on VS2003.
error C2248: 'A::y' : cannot access protected member declared in class 'A'
class A
{
public:
A() : x(0), y(0) {}
protected:
int x;
int y;
};
class B : public A
{
public:
B() : A(), z(0) {}
B(const A& item) : A(), z(1) { x = item.y;}
private:
int z;
};
The problem is with x = item.y;
The access is specified as protected. Why doesn't the constructor of class B have access to A::y?
It's because of this:
class base_class
{
protected:
virtual void foo() { std::cout << "base::foo()" << std::endl; }
};
class A : public base_class
{
protected:
virtual void foo() { std::cout << "A::foo()" << std::endl; }
};
class B : public base_class
{
protected:
virtual void foo() { std::cout << "B::foo()" << std::endl; }
public:
void bar(base_class *b) { b->foo(); }
};
If that were legal, you could do this:
A a;
B b;
b.bar(&a);
And you'd be calling a protected member of A from B, which isn't allowed.
The other answers explain the reasoning behind preventing your B object from accessing the protected parts of A in your example, even though B 'is-a' A. Of course, the easiest way to fix this problem is to make the parts of A you want access topublic` or have publicly accessible accessor methods.
However you might decide that's inappropriate (or you might not have control over the definition of A). Here are some suggestions to let you work around the problem, in increasing order of subverting A's access control. Note that all of these workarounds assume that class A is copy-constructable.
In the first case, you simply use the copy constructor for A to set up an initial state for that part of the B object, then fix it up afterward:
class B1 : public A
{
public:
B1() : A(), z(0) {}
B1(const A& item) : A(item), z(1) {
// fix up the A sub-object that was copy constructed
// not quite the way we wanted
x = y;
y = 0;
}
private:
int z;
};
I find that incredibly confusing and probably very error prone (assuming that we want the A sub-object in the B object to be different than the A object being passed to the constructor - an unusual situation, but it's what was given in the problem). However, the fact that it can be done gives some justification for the more subversive examples that follow...
The next example creates a temporary B object that has an exact duplicate of the A object we want access to. We can then use the temporary B object to get to the items that were protected:
class B2 : public A
{
public:
B2() : A(), z(0) {}
B2(const A& item) : A(), z(1) {
// create a special-use B2 object that can get to the
// parts of the A object we want access to
B2 tmp( item, internal_use_only);
x = tmp.y; // OK since tmp is of type B
}
private:
int z;
// create a type that only B2 can use as a
// 'marker' to call a special constructor
// whose only purpose in life is to create
// a B object with an exact copy of another
// A sub-object in it
enum internal_use {
internal_use_only
};
B2( const A& item, internal_use marker) : A(item), z(0) {};
};
I find that solution to be a bit less confusing than the first, but it's still confusing (in my opinion). Having a bastard version of of B object just to get to the parts of the A object we want is odd.
We can do something about that by creating a special proxy for A objects that gives the access we want. Note that this is the 'most subversive' workaround because it's something that any class could do to get to protected parts of A, even if they aren't sub-classes of A themselves. In the case of the B class, there's some legitimacy to getting to the protected parts of A objects, since B is-a A, and as we've already seen there are workarounds that let us get access that use only rights that class B already has, so I consider this a cleaner version of those workarounds in class B's case.
class B3 : public A
{
public:
B3() : A(), z(0) {}
B3(const A& item) : A(), z(1) {
// a special proxy for A objects that lets us
// get to the parts of A we're interested in
A_proxy tmp( item);
x = tmp.get_y();
}
private:
int z;
class A_proxy : public A
{
public:
A_proxy( const A& other) : A(other) {};
int get_x() {return x;};
int get_y() {return y;};
};
};
IBM's documentation summarizes it best:
A protected nonstatic base class
member can be accessed by members and
friends of any classes derived from
that base class by using one of the
following:
A pointer to a directly or indirectly derived class
A reference to a directly or indirectly derived class
An object of a directly or indirectly derived class
Thus, using your example above as the basis:
B::B(const A& item) : A(), z(1) {
// NOT OK because `item` is not a reference to the derived class B
//int i = item.y;
// OK because `item` reinterpreted as a reference to the derived class B
// Do not do this (bad!) -- for illustrative purposes only
int i = reinterpret_cast< const B& >(item).y;
// OK because it is equivalent to `this->x = i`,
// where `this` is a pointer to the derived class B
x = i;
}