I want to extend my base class by adding some possible postprocessing or preprocessing in some important util functions, and at the same time, I want to ensure that, calls to base class member function invokes the overridden functions of the most derived class.
These two ideas are what I'm considering of;
Add preprocess() and postprocess() of derived class
void func() {
derived().func_pre();
// do the job of the base class
derived().func_post();
}
Truly awful, all derived class should implement func_pre() and func_post() even if they don't need.
Call derived().func() from func()
Base class:
void func() {
derived().func()
}
void func_impl() {
// do the job of the base class
}
Derived class:
void func() {
preprocess();
base().func_impl();
postprocess();
}
Better than idea 1, but func() will be ill-formed if there is no CRTP derived class.
Better ideas?
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
I have to make a base class with one derived class in C++. In the end I need to evidence polymorphism between 2 methodes void Read and void Show.
After I did this, I have to create an abstract class Object from which the base class will be derived.This class will contain just pure virtual methods Read and Show.
I don't think I fully understand this. So I make an abstract class Object where I put these 2 methods with "=0" to mke them pure. But this means that I have to edit the base class also, to make it derived from class Object? Like, before:
class Base {
}
after
Class Base : public Object
Can someone make me understand?
You're on the right track. In your Base class, you can mark methods virtual that you intend to be polymorphic. You can set the functions = 0 if they are "pure virtual" and have no implementation in the base class, and are required in any concrete derived class.
class Base
{
public:
virtual void Read() = 0;
virtual void Show() = 0;
};
Then for your derived class you had the syntax backwards. Note that the override keyword indicates that you are overriding a virtual method from the base class. This keyword enforces that the function signature matches the one from a base class.
class Object : public Base
{
public:
void Read() override; // implement this
void Show() override; // implement this
};
The usage could look like the following. Note that you instantiate an Object but carry a pointer to a Base*. Due to polymorphism, the derived implementations are invoked.
int main()
{
Object obj;
Base* p = &obj;
p->Read(); // due to polymorphism will call Object::Read
p->Show(); // due to polymorphism will call Object::Show
}
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 am trying to allow a child class to define the variadic function specialization. For example:
#include <iostream>
#include <vector>
#include <memory>
class BaseClass
{
public:
BaseClass() {};
virtual ~BaseClass() {};
template<typename GenericData>
void ReceiveData(GenericData &inData)
{
throw std::runtime_error("Undefined");
}
};
class ReceiveInt : public BaseClass
{
void ReceiveData(int & inData)
{
std::cout << "I know what to do!";
}
};
int main(int argc, char* argv[])
{
std::vector<std::shared_ptr<BaseClass>> classHolder;
classHolder.push_back(std::make_shared<ReceiveInt>());
int test = 1;
classHolder.front()->ReceiveData(test);
return 0;
}
But unfortunately this does not work, as the BaseClass ReceiveData function is called. Is this even possible?
EDIT 1
As people have pointed out, I'm very wrong with my notation. Looks like I learned more than I expected today.
Is this even possible?
I don't think so.
Dynamic dispatch is possible only for virtual member functions.
Member function templates may not be virtual.
If you can use regular member functions, i.e. not member function templates, then you can make them virtual. That will work.
You confuse some notions here.
To start with, there are no variadic templates here as ReceiveData function below:
template<typename GenericData>
void ReceiveData(GenericData &inData)
{
throw std::runtime_error("Undefined");
}
is a template member function.
Then, if you want to override a method in the derived class, the right way is to use virtual functions, probably a pure virtual function in the base class and a virtual function with an override specifier in the derived class.
However, virtual functions limit you to a a set of fixed types because there are no template virtual functions. You could experiment with CRTP though:
template<typename T>
class Base {
public:
void receiveData(const T&) {}
};
class ReceiveInt : public Base<int> {};
which emulates a sort of static polymorphism. Below:
ReceiveInt{}.receiveData(int{});
receiveData from the base class instantiated with int.
I think you may be confusing your terminology. BaseClass::ReceiveData is a templated method, taking a template parameter GenericData. A variadic function takes a number of arguments determined at runtime.
In ReceiveInt, you're not making a specialization of anything, because ReceiveInt::ReceiveData is not a templated method. In fact, even if it was templated, it would not be possible to call in your example. How would a pointer to BaseClass know how to call a template specialization in the derived class it points to?
You can make BaseClass::ReceiveData virtual. This allows you to override it in a base class, and still call it with a pointer to BaseClass. Unfortunately, templates are a compile time language feature, whereas dynamic dispatch is a runtime feature -- in this context, you can't have both.
References
Variadic Functions
Template Specialization
Why do we need virtual functions in C++?
You would have to cast to the derived type first, it is not possible using a base class pointer/reference as the base class will only know about its own implementation. This is not even a case where you can use a recursive dependency on the derived type as the derived type is not defined yet at the point the base is being instantiated.
If you do cast to the derived type then it would be able to resolve the derived member as you desire.
There is no variadic templates in your code like already explained by the others.
But you can use the fact that the templated class methods are instantiated at the first time invoked. But there is no virtual overriding here.
In this example you can define the different implementations of the method templates in Base and Derived classes, but you have explicitely tell the compiler which one to use.
It's not possible to use Derived class method through a Base class pointer without explicit cast:
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
Base() {};
virtual ~Base() {};
template<typename T>
void ReceiveData(T)
{
throw std::runtime_error("Undefined");
}
};
class Derived : public Base
{
public:
template<typename... Args >
void ReceiveData(Args... args)
{
(void)std::initializer_list<int>{(std::cout << args << std::endl, 0)...};
}
};
int main()
{
Base b;
// b.ReceiveData(1); //-> this calls base class method
Derived d;
d.ReceiveData(1); // this calls the method in the derived class
d.ReceiveData(2, "hello"); // this calls the method in the derived class
Base* b2 = new Derived();
// b2->ReceiveData(3); // this will instantiate and call the base class method
// thus raising an exception
// because no virtual overriding of templated methods
((Derived*)b2)->ReceiveData("world",1); // this will instantiate and call the derived class
// method, then because of explicit casting the
// compiler knows which class to target
return 0;
}
Live demo: https://wandbox.org/permlink/K0qEAC7C7yzg6gYL
Is there a way you can invoke a member function of a base class upon a class derived from it?
Class Bass{
public:
void func();
};
Class Derived: public Base{
public:
void func();
};
I have a practice midterm, and I suspect no, because how would the Base class know about the Derived, but I am not sure.
Is there a way you can invoke a member function of a base class upon a class derived from it?
Not sure exactly what you mean by this, but given your Base and Derived classes you can do the following. Just make sure you use a reference or pointer, not pass-by-value because of the slicing problem.
Call Base::func() from within Derived::func():
void Derived::func()
{
Base::func();
}
Call Base::func() explicitly on a Derived object:
Derived d;
d.Base::func();
I [...] am wondering if you could do something like Base::func(Derived d)
As others have pointed out, you can do this using a forward declaration:
// Tell the compiler "Derived" is a class name.
class Derived;
class Base
{
// Can use the class name since it has been declared.
void func(Derived& derived);
};
// Define the class named "Derived".
class Derived : public Base
{
// ...
};
// Use the derived class.
void Base::func(Derived& derived)
{
// For this bit to work, the definition of `Derived` must
// be visible at this point (like putting the class above
// or including your "Derived.h" from "Base.cpp").
derived.some_derived_method();
}
However, you won't be able to define the Base::func(Derived&) directly in the class definition since you need to finished defining Base and to define Derived first.
if I understand correctly, you need to call base function with derived parameter?
You can do it only using forward declaration and passing derived object by pointer or ref.
class Derived;
class Base{
public:
void func(Derived&);
};
You should be able to do something like this:
class Derived;
class Base {
public:
void func();
void func(Derived);
};
class Derived : public Base {
public:
void func();
};
void
Base::func(Derived D) {
}
It is okay to use incomplete types in the Base's member function declarations, but you must provide the complete type before their definition.
You can use forward declaration of Derived class:
class Derived;
First of all, do you mean methods on an object, or static class methods?
Secondly, the answer is: it depends what the object you're invoking the method call on is. This is the nature of polymorphism: if your object is of type 'Derived', then even if it has been cast to a 'Base' the method call will still invoke the Derived version of func.
Is that what you were asking?