while reading through vptr and vtable concept i got this wonderful piece of code, but i am not able to make out the concept involved here:
#include <iostream>
using namespace std;
class A
{
public:
virtual void foo(int x = 10)
{
cout << "base x : " << x << "\n";
}
virtual void bar()
{
cout << "base bar\n";
}
};
class B : public A
{
public:
virtual void foo(int x = 20)
{
cout << "derived x : " << x << "\n";
}
private:
virtual void bar()
{
cout << "derived bar\n";
}
};
class C : public B
{
};
int main()
{
A x; x.foo(); // x.foo(10);
B y; y.foo(); // x.foo(20);
A *p(&y);
p->foo();
}
now the output i get here is:
base x : 10
derived x : 20
derived x : 10
how is it possible that even when derived x(i.e B::foo()) is being printed then the default argument is that of base function(i.e A::foo())?
C++ standard section 8.3.6 point 10 mentions that:
A virtual function call (10.3) uses the default arguments in the
declaration of the virtual function determined by the static type of
the pointer or reference denoting the object. An overriding function
in a derived class does not acquire default arguments from the
function it overrides.
In your example the evaluation of default argument is done on the basis of type of "p" which is "A". Hence the evaluation of default argument is done from the declaration of A, and the calling of function happens by the usual lookup in vptr table.
It seems that the default parameters are resolved at compile time. See here and here.
The default values that are used will be those defined in the static (compile-time) type. So if you were to change the default parameters in an override, but you called the function through a base class pointer or reference, the default values in the base would be used.
Related
I have a problem with a final function. I want to "stop" the polymorphism in a class but I still want to generate the same function in a derived class.
Something like this:
class Base{
protected:
int _x, _y;
public:
Base(int x = 0, int y = 0) : _x(x), _y(y){};
int x() const { return _x; }
int y() const { return _y; }
virtual void print()const{ cout << _x*_y << endl; }
};
class Derived : public Base{
public:
Derived(int x = 0, int y = 0) : Base(x, y){}
void print()const final { cout << _x*_y / 2.0 << endl; } // final inheritance
};
class NonFinal : public Derived{
void print()const{ cout << "apparently im not the last..." << endl }
// here i want a new function. not overriding the final function from Derived class
};
I think this is an experimental question, since actually you should rethink what you are doing when you require to "override a final function" (sounds contradicting, doesn't it?).
But you could introduce a "dummy"-parameter, i.e. void NonFinal::print(int test=0)const, which let's the compiler treat the member function as a different one. Not sure if that solves your "problem"; but at least it introduces a function with the same name, which can still be called without passing an argument, and which is separated from the ones of Derived and Base.
class NonFinal : public Derived{
public:
void print(int test=0)const{ cout << "apparently im not the last..." << endl; }
};
int main() {
Base b (10,10);
Derived d (20,20);
NonFinal nf;
Base *bPtr = &d;
bPtr->print(); // gives 200
bPtr = &nf; // gives 0
bPtr->print();
nf.print(); // gives "apparantly..."
}
Sorry, but it's not possible to create a function in a derived class when a function with the same name exists as final in the base class. You'll need to rethink your design.
The problem stems from the fact that a function declaration in a derived class with the same name as a function in a base class is treated as an attempt to override whether the override keyword is present or not (for historical reasons, I presume). So you can't "turn off" overriding.
Here's a relevant standard quote:
§ 10.3/4 [class.virtual]
If a virtual function f in some class B is marked with the virt-specifier final and in a class D derived from B a function D::f overrides B::f, the program is ill-formed. [ Example:
struct B {
virtual void f() const final;
};
struct D : B {
void f() const; // error: D::f attempts to override final B::f
};
—end
Looking for an explanation of some fact in the standard I found this:
An abstract class (10.4) is never a most derived class, thus its
constructors never initialize virtual base classes, therefore the
corresponding mem-initializers may be omitted.
This is from the paragraph 12.6.2 of the final working draft. Since, It's embedded in Note and no example is provided, I don't know how it should be treated. So, I tried the example:
#include <iostream>
struct B{
~B(){}
B(){ std::cout << "B()" << std::endl; }
B(int){ std::cout << "B(int)" << std::endl; }
};
struct A : virtual B
{
int s;
virtual void foo() = 0;
A(int a) : B(a) { std::cout << "A(int)" << std::endl; }
};
struct D : A{
D() : A(10){ }
virtual void foo(){ }
} d;
int main()
{
}
and got the output
B()
A(int)
http://coliru.stacked-crooked.com/a/b16c68226f072ced
in spite of specifying the B's constructor in the ctor-initializer. Is that what they mean?
In this example, D is the most derived class and will construct B using the default (no parameter) constructor.
An abstract class is never most derived because you have to derive from it in order to instantiate it.
Suppose I have
struct C {
C() { init(); };
void init() { cout << "C" << endl; };
};
struct D : public C {
D() : C() { };
void init() { cout << "D" << endl; }
};
D();
why I get "C" printed? How can change this behaviour (and get "D").
How if I want both?
why I get "C" printed?
C::init() is not declared as virtual, so D cannot override it. But even if C::init() were declared as virtual, D::init() would still not be called when init() is called inside of C's constructor.
C++ constructs base classes before derived classes (and destructs derived clases before base classes). So C's constructor runs before D is constructed (and C's destructor runs after D is destructed). The VMT of the object being constructed/destructed simply does not point at D's method table when C is being constructed/destructed, it points at C's method table instead.
How can change this behaviour (and get "D").
You cannot call a derived virtual method from inside of a base class constructor/destructor. The VMT does not contain a pointer to the derived class method table at those stages.
You have a quite fundamental problem here: You want to call a member function of a derived class on an object that does not exist yet.
Remember that objects are constructed by first constructing the base sub-object and then the derived object. So even if you'd manage to apply a “clever” trick to actually invoke the derived class' init function, as soon as that function would try to access any data member of the derived object, it would cause arbitrary damage. On the other hand, it is fine to access only the base object, as long as you don't rely on any invariant that the constructor has not established yet. Therefore, if you don't need access to the derived object's data, you can make the init function static and pass it a reference to the base class object.
Maybe this is coming close to what you are trying to do.
#include <iostream>
struct Base
{
Base(void (*fp)(Base&) = Base::init) { fp(*this); }
static void init(Base&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
struct Derived : Base
{
Derived() : Base(Derived::init) { }
static void init(Base&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
int
main()
{
Base b {};
std::cout << std::endl;
Derived d {};
}
Output:
static void Base::init(Base&)
static void Derived::init(Base&)
Here, the base class constructor takes a function pointer to an initializer function that takes a reference to a Base object. The function defaults to Base::init but derived classes can replace it. Be aware, however, that in this design, the Base class constructor may not safely assume that any side effect of Base::init actually took place. It is fine as an extension mechanism (if Base::init does nothing or is disposable), though.
But I doubt that you need to use this kind of machinery. If all you want to do – and this should be the normal case – is to first initialize the base object and then the derived object, C++ already will do the right thing by default if you simply call the functions from the respective constructors.
struct Base
{
Base() { this->init(); }
void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
struct Derived : Base
{
Derived() { this->init(); }
void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
// main() as above ...
Output:
void Base::init()
void Base::init()
void Derived::init()
And if we only want to call the most derived class' init function, we can simply tell the base class not to run its own.
struct Base
{
Base(const bool initialize = true) { if (initialize) this->init(); }
void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
struct Derived : Base
{
Derived() : Base(false) { this->init(); }
void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
// main() as above ...
Output:
void Base::init()
void Derived::init()
You only can remove init() from C constructor to not print "C".
To also print "D" add init() in D() constructor.
If for some cases you want print "C" or "D" and in some don't do something like this
struct C {
C() { };
void init() { cout << "C" << endl; };
};
struct D : public C {
D() : C()
{
if(some condition)
C::init();
if(some condition)
init();
};
void init() { cout << "D" << endl; }
};
D();
I read about the inheritance mechanism in C++ and about virtual functions.
according to my knowlendge (in all examples I have encountered), inherited methods had the same signature as the parent class'.
My question is the following:
I know that function default parameter value is not a part of function signature.
Can I define this value to be some constant in the parent Class virtual function, and in the derived class declare and implement the overriding method without this default value.
In this case, when I call the derived object's method using a pointer to parent class, will the function be called with/without this default initializion?
thanks
Default arguments are mostly syntactic sugar and get determined at compile time. Virtual dispatch, on the other hand, is a run-time feature. It would probably be least surprising to have that default parameter chosen that was defined alongside with the function that actually gets called but this is not possible (at least not without additional run-time overhead) for the reason stated above.
Therefore, the default parameter is selected by the compiler using the static type of the object a member function is called upon. Let's see an example.
#include <iostream>
#include <memory>
class Base
{
public:
virtual void
f(int a, int b = 1)
{
std::cout << "Base: a = " << a << ", b = " << b << "\n";
}
};
class Derived : public Base
{
public:
virtual void
f(int a = 1, int b = 2) override
{
std::cout << "Derived: a = " << a << ", b = " << b << "\n";
}
};
int
main()
{
std::unique_ptr<Base> base_as_base {new Base {}};
std::unique_ptr<Base> derived_as_base {new Derived {}};
std::unique_ptr<Derived> derived_as_derived {new Derived {}};
base_as_base->f(0); // Base: a = 0, b = 1
derived_as_base->f(0); // Derived: a = 0, b = 1
// derived_as_base->f(); // compiler error
derived_as_derived->f(0); // Derived: a = 0, b = 2
derived_as_derived->f(); // Derived: a = 1, b = 2
}
I agree that this is confusing. Please don't write code like this. Fortunately, there is a simple workaround. Apart from not using default parameters at all, we can use an idiom called non-virtual interfaces. The virtual function is made protected and not given any default parameters. It is then only called indirectly by a non-virtual function from the base class. That function can have all default parameters defined in a single place.
#include <iostream>
#include <memory>
class Base
{
public:
void
f(int a, int b = 1)
{
this->impl(a, b);
}
protected:
virtual void
impl(int a, int b)
{
std::cout << "Base: a = " << a << ", b = " << b << "\n";
}
};
class Derived : public Base
{
protected:
virtual void
impl(int a, int b) override
{
std::cout << "Derived: a = " << a << ", b = " << b << "\n";
}
};
int
main()
{
std::unique_ptr<Base> base_as_base {new Base {}};
std::unique_ptr<Base> derived_as_base {new Derived {}};
std::unique_ptr<Derived> derived_as_derived {new Derived {}};
base_as_base->f(0); // Base: a = 0, b = 1
derived_as_base->f(0); // Derived: a = 0, b = 1
derived_as_derived->f(0); // Derived: a = 0, b = 1
}
This is what I found from the C++ Draft Standard N3337:
8.3.6 Default arguments
10 A virtual function call (10.3) uses the default arguments in the declaration of the virtual function determined by the static type of the pointer or reference denoting the object. An overriding function in a derived class does not acquire default arguments from the function it overrides. [ Example:
struct A {
virtual void f(int a = 7);
};
struct B : public A {
void f(int a);
};
void m() {
B* pb = new B;
A* pa = pb;
pa->f(); // OK, calls pa->B::f(7)
pb->f(); // error: wrong number of arguments for B::f()
}
—end example ]
Coming to your question:
Can I define this value to be some constant in the parent Class virtual function,
Yes
and in the derived class declare and implement the overriding method without this default value
Yes.
However, when you call the function using a derived class pointer, you'll have to provide an argument. When you call the function using a base class pointer, you don't need to provide an argument.
#include <iostream>
using namespace std;
class Base {
public:
virtual void some_func(int f1)
{
cout <<"Base is called: value is : " << f1 <<endl;
}
};
class Derived : public Base {
public:
virtual void some_func(float f1)
{
cout <<"Derived is called : value is : " << f1 <<endl;
}
};
int main()
{
int g =12;
float f1 = 23.5F;
Base *b2 = new Derived();
b2->some_func(g);
b2->some_func(f1);
return 0;
}
Output is :
Base is called: value is : 12
Base is called: value is : 23
Why is the second call b2->some_func(f1) calling Base class's function,even though there is a version with float as argument available in Derived class?
It's not actually overridden, since its arguments don't have the same type.
Since it's not overridden, your pointer to Base only knows the int method, so it performs a narrowing conversion (there should be a warning) and calls Base::some_func(int).
you have confused overloading with overriding ,
For overriding , the signature of the function must remain same.
please check the c++ documentation again .. hope this is helpful