I know that when you want to declare a polymorphic function you have to declare the base class function virtual.
class Base
{
public:
virtual void f();
};
My question is are you required to declare the inheriting class function as virtual, even if it's expected that Child behaves as if it were "sealed"?
class Child : public Base
{
public:
void f();
};
No, you don't need to re-declare the function virtual.
A virtual function in a base class will automatically declare all overriding functions as virtual:
struct A
{
void foo(); //not virtual
};
struct B : A
{
virtual void foo(); //virtual
}
struct C : B
{
void foo(); //virtual
}
Declaring f() as virtual in Child helps some one reading the definition of Child. It is useful as documentation.
Once the base class override is marked as virtual all other overrides are implicitly so. While you are not required to mark the function as virtual I tend to do so for documentation purposes.
As of the last part: even if it's expected that Child behaves as if it were "sealed"?, if you want to seal the class, you can actually do it in C++11 (this was not fully implementable in C++03 generically) by creating a seal class like so:
template <typename T>
class seal {
seal() {}
friend T;
};
And then inheriting your sealed class from it (CRTP):
class Child : public Base, virtual seal<Child> {
// ...
};
The trick is that because of the use of virtual inheritance, the most derived type in the hierarchy must call the virtual base constructor (int this case seal<Child>), but that constructor is private in the templated class, and only available to Child through the friend declaration.
In C++ you would have to either create a seal type for every class that you wanted to seal, or else use a generic approach that did not provide a perfect seal (it could be tampered with)
Related
I was wondering how can one explain this mechanism:
class Base{
class Other;
virtual void test() = 0;
};
class Other: Base{
virtual void test() override;
};
void Other::test(){ /*do something*/}
It looks like I have a base class called Base. It contains of a nested class which inherits from the Base. So if I call:
Base obj;
obj.test(); <-- it trigers the test() function from the Other class, doesn't it?
What is the difference between the given example and the following:
class Base{
virtual void test() = 0;
};
class Other: Base{
virtual void test() override;
};
void Other::test(){ /*do something*/}
what would be the benefit of hidding the Other class in the Base class?
class Base{
virtual void test() = 0;
};
Base obj; // #0
#0 is ill-formed as Base is an abstract class, as it has at least one pure abstract member function.
Abstract class
Defines an abstract type which cannot be instantiated, but can be
used as a base class.
A pure virtual function is a virtual function whose declarator has the
following syntax:
declarator virt-specifier(optional) = 0
[...] An abstract class is a class that either defines or inherits
at least one function for which the final overrider is pure virtual.
Dynamic dispatch on polymorphic objects happens when you are dispatching to a virtual function from a base pointer or reference, which (for the specific runtime call) references a derived object.
In the following example:
struct Base {
virtual void test() const = 0;
};
struct A final : public Base {
void test() const override {}; // #1
};
struct B final : public Base {
void test() const override {}; // #2
};
void f(Base const& b) {
b.test(); // #3
}
the call to the virtual member function test() at #3 can dispatch to either A::test() or B::test(), depending on the argument to the function f.
f(A{}); // 'test()' call in 'f' dispatches to #1
f(B{}); // 'test()' call in 'f' dispatches to #2
what would be the benefit of hidding the Other class in the Base class?
In your original example, the Base class declares a nested class (but does not define it) to itself, meaning the Other class declared in Base is not the same as the Other class that derives from it.
Declaring nested classes within a class is a separate topic entirely orthogonal to class inheritance hierarchies
A forward declaration outside of a base class that intends to forward declare a derived class that the base class thinks may derive from it would be an anti-pattern, as the whole point with abstract (interface) classes is to provide a public client API that can be used polymorphically by different derived classes. In other words, a base class should generally never (need to) know about its derived classes (save for the special case of static polymorphism via the curiously recurring template pattern).
The declaration of class Base::Other at line 2 in your first code example, has nothing to do with the declaration of class Other in line 5 of your first code example.
That is, the forward declaration of Base::Other does not match class Other.
There is benefit in having nested classes (for example, some implementations of the pimpl idiom do that), but to define the nested class, you would have to define it with:
class Base::Other {...}; // explicit specification of Base here
Is there any point to making virtual member functions, overridden from a base class private, if those are public in the base class?
struct base {
virtual void a();
};
struct derived : base {
// ...
private:
void a() override;
};
If you are forced to do a 2-phase construction on the implementation class (i.e. have an init() method as well as or instead of a constructor that has to be called (I know, but there are reasons), then this stops you calling any /other/ methods directly on the instance pointer before you pass it back as an interface pointer. Go the extra mile, make the inheritance private, and have your one public init function return the interface pointer!
Another reason is you just don't /need/ to write public: in a final implementation class declaration, so then by default everything is private. But why you would do that and use struct instead of class I don't know. Perhaps this was converted from class at some point due to a style war?
Looking at your design, I see one cannot call derived::a directly, but only through a base interface.
Is there any point? Consider that, once we have a derived instance, we can always up-cast to its base, so given
derived d;
while d.a() wouldn't compile, we can always do
base & b = d;
b.a(); //which actually calls derived::a
In other words: derived::a is not that private, after all, and I would discourage this design, which can be confusing to the user.
Things change if the members private in derived are private in base, as well: this time it is clear that they just cannot be called directly, outside base or derived.
Let's say we have a couple of functions, and want them to be called conditionally, according to a value passed as an argument to a third one:
struct base
{
void dosomething(bool x)
{
if(x)
{
do_this();
}
else
{
do_that();
}
}
private:
virtual void do_this(){}
virtual void do_that(){}
};
Thus a derived class could be like:
struct derived : base
{
private:
void do_this() override { }
void do_that() override { }
};
and no other class can call them, unless it extended base itself:
derived d;
d.dosomething(true); //will call do_this() in derived
d.dosomething(false); //will call do_that() in derived
d.do_that() //won't compile
Yes, if you inherit the base class as private. Otherwise, it is more of a weird explicit-like restriction - user has to has to make an explicit conversion to use the function - it is generally ill advised as few will be able to comprehend the author's intention.
If you want to restrict some functions from base class, make a private/protected inheritance and via using keyword declare which base-methods you want to be protected/public in the derived class.
The same reasoning as for non-virtual methods applies: If only the class itself is supposed to call it make it private.
Consider the template method pattern:
struct base {
void foo() { a() ; b(); }
virtual void a() = 0;
virtual void b() = 0;
};
struct derived : base {
private:
void a() override {}
void b() override {}
};
int main()
{
derived().foo();
}
Perhaps a and b should have been protected, but anyhow the derived can change accesibility and it requires some documentation so that derived knows how it is supposed to implement a and b.
I have an abstract base class and want to implement a function in the derived class. Why do I have to declare the function in the derived class again?
class base {
public:
virtual int foo(int) const = 0;
};
class derived : public base {
public:
int foo(int) const; // Why is this required?
};
int derived::foo(int val) const { return 2*val; }
Consider that the derived-class definition might be in a header, whereas its implementation may be in a source file. The header typically gets included in multiple locations ("translation units"), each of which will be compiled independently. If you didn't declare the override, then the compiler wouldn't know about it in any of those other translation units.
The intention of making a function pure virtual in Base class is that the derived class must override it and provide its own implementation.
Note that presence of an pure virtual function in the class makes that class an Abstract class. In simple terms the class acts as an interface for creating more concrete classes.One cannot create objects of an Abstract class.
If you do not override the pure virtual function in derived class then the derived class contains the inherited Base class pure virtual function only and it itself acts as an Abstract class too.Once your derived class is abstract it cannot be instantiated.
So in order that your derived class be instantiated it needs to override and hence declare the pure virtual function.
You might think the compiler can deduce that you're going to have to provide an implementation of derived::foo(), but derived could also be an abstract class (and in fact that's what you'll get if you dont declare foo() in derived)
It is to override the abstraction of the base class.
If you do not re-declare it, then your derived class is also an abstract class. If you do then you now have a non-abstract type of the base.
Because the hierarchy could have more layers.
struct Base {
virtual void foo() const = 0;
virtual void bar() const = 0;
};
struct SuperBase: Base {
virtual void bar() const override;
};
struct Concrete: SuperBase {
virtual void foo() const override;
};
Here, SuperBase does not provide an implementation for foo, this needs be indicated somehow.
While you can't instantiate a class with pure virtual functions, you can still create a class like this:
class base {
public:
virtual int foo(int) const = 0;
};
class derived : public base {
public:
};
class very_derived : public derived {
public:
virtual int foo(int) const { return 2; }
};
The derived class is still an abstract class, it can't be instantiated since it doesn't override foo. You need to declare a non-pure virtual version of foo before you can instantiate the class, even if you don't define foo right away.
I don't understand why the compiler doesn't like this, here is and example of the problem:
class A
{
public:
virtual void Expand() { }
virtual void Expand(bool flag) { }
};
class B : public A
{
public:
virtual void Expand() {
A::Expand(true);
Expand(true);
}
};
When I try to compile this the A::Expand(true); compiles fine, but the non scoped Expand(true); gets this compiler error:
'B::Expand' : function does not take 1 arguments
You don't need virtual methods for that behaviour. Methods in a derived class hide methods with the same name in the base class. So if you have any function named Expand in your derived class (even if it is an override of a virtual method from the base class), none of the base classes methods with the same name are visible, regardless of their signature.
You can make the base classes methods visible with using. For that you would add using A::Expand; to the definition of B:
class B : public A
{
public:
using A::Expand;
virtual void Expand() { Expand(true); }
};
That's because besides overriding the base Expand(), you're also hiding the base Expand(bool).
When you introduce a member function in a derived class with the same name as a method from the base class, all base class methods with that name are hidden in the derived class.
You can fix this by either qualifying (as you have) or with the using directive:
class B : public A
{
public:
using A::Expand;
virtual void Expand() {
A::Expand(true);
Expand(true);
}
};
I know why I want to use private virtual functions, but how exactly can I implement them?
For example:
class Base{
[...]
private:
virtual void func() = 0;
[...]
};
class Derived1: public Base{
void func()
{ //short implementation is ok here
}
};
class Derived2: public Base{
void func(); //long implementation elsewhere (in cpp file)
};
[...]
void Derived2::func()
{ //long implementation
}
The first version is ok but not always possible.
Isn't the second version simply name hiding? How do you define the Base::func() of Derived2, if you cannot do it within the class declaration of Dereived2?
Thanks
How do you define the Base::func() of Derived2, if you cannot do it within the class declaration of Dereived2?
You don't define "Base::func() of Derived2" (whatever this might be), you define Derived2::func(). This compiles just fine for me:
#include <iostream>
class Base{
private:
virtual void foo() = 0;
public:
void bar() {foo();}
};
class Derived: public Base{
void foo();
};
void Derived::foo()
{
std::cout << "inside of 'Derived1::foo()'\n";
}
int main()
{
Derived d;
Base& b = d;
b.bar();
return 0;
}
What's your problem with it?
Polymorphism and accessibility are two separate concepts. You can always override a base class' private virtual function, but you won't be able to call the base class version from anywhere but the base class itself. Also, C++ FAQ Lite has a pretty lengthy entry on the subject.
For what I understand here, you're trying to do polymorphism.
There are 4 rules that you must follow to achieve polymorphism.
You must inherit from the base class.
Your functions must have the same name in every class.
You need the virtual keyword in front of every function, and the override keyword at the end of the child's fonctions.
You have to use a pointer on the main class, and use the "new" keyword to define it as a child type.
See this awesome wiki page for code example.
Hope this is what you wanted. ^^
Yours truly,
SeargX