I'll start by explaining my situation.
I have a base class that automatically implements a type of reference counting. It allows me to wrap C-style init() and free() library calls into a reference-counted API.
template<typename T>
class Service {
public:
Service() {
if(s_count++ == 0) {
T::initialize();
}
}
~Service() {
if(--s_count == 0) {
T::terminate();
}
}
private:
static int s_count;
};
template<typename T>
int Service<T>::s_count = 0;
Classes that wish to implement these initializers and terminators will derive from Service like so:
class Test : public Service<Test> {
friend class Service<Test>;
private:
static void initialize() {
std::cout << "Initialized" << std::endl;
}
static void terminate() {
std::cout << "Terminated" << std::endl;
}
};
However, the declaration is messy since I have to both inherit from and friend my Service class. Is there any way to allow a base class access to protected or private members of a derived class automatically? If not, I may as well ask if there's any better way to write what I've done here.
"Is there any way to allow a base class access to protected or private members of a derived class automatically?"
Base class cannot access private/protected members of derived class formally. In general base classes are designed such a way that they don't need to know anything of derived class. So, if there is a need to access members in derived class from your base class then you should re-consider your design.
EDIT ( As per proposed article by #RSahu ):-
Although there are some scenario where it might be useful to access member functions of derived class from base class. Like when you are sharing objects between two processes.
#include <iostream>
using namespace std;
template<typename T>
class Service {
struct TT: T {
using T::initialize;
using T::terminate;
};
public:
Service() {
if(s_count++ == 0) {
TT::initialize();
}
}
~Service() {
if(--s_count == 0) {
TT::terminate();
}
}
private:
static int s_count;
};
class Test : public Service<Test> {
//friend class Service<Test>;
protected:
static void initialize() {
std::cout << "Initialized" << std::endl;
}
static void terminate() {
std::cout << "Terminated" << std::endl;
}
};
template<typename T>
int Service<T>::s_count = 0;
int main() {
Test t;
}
n.m.'s suggestion of making these methods virtual made me think: it would not work by itself, but it would work if you decouple the service from its management: the initialization doesn't just applies to that particular service instance, it applies to all instances, and perhaps because of that it just shouldn't be part of the service class in the first place.
If you decouple them, you can make a service manager base class, with virtual methods that a derived service manager must implement, like so:
#include <iostream>
class ServiceManager {
template <typename T>
friend class Service;
virtual void initialize() = 0;
virtual void terminate() = 0;
};
template <typename T>
class Service {
public:
Service() {
if (s_count++ == 0) {
s_manager.initialize();
}
}
~Service() {
if (--s_count == 0) {
s_manager.terminate();
}
}
private:
static int s_count;
static ServiceManager &&s_manager;
};
template <typename T>
int Service<T>::s_count = 0;
template <typename T>
ServiceManager &&Service<T>::s_manager = T();
class TestManager : public ServiceManager {
void initialize() {
std::cout << "Initialized" << std::endl;
}
void terminate() {
std::cout << "Terminated" << std::endl;
}
};
class Test : public Service<TestManager> {
};
If your compiler doesn't support this use of && (it's valid C++11, but not valid C++03), you should still be able to easily adapt the code by either making s_manager ServiceManager & and not using a temporary T to initialise it, or just making s_manager have type T. The former is more verbose, the latter allows T implementations that do not derive from ServiceManager.
Related
I'll start by explaining my situation.
I have a base class that automatically implements a type of reference counting. It allows me to wrap C-style init() and free() library calls into a reference-counted API.
template<typename T>
class Service {
public:
Service() {
if(s_count++ == 0) {
T::initialize();
}
}
~Service() {
if(--s_count == 0) {
T::terminate();
}
}
private:
static int s_count;
};
template<typename T>
int Service<T>::s_count = 0;
Classes that wish to implement these initializers and terminators will derive from Service like so:
class Test : public Service<Test> {
friend class Service<Test>;
private:
static void initialize() {
std::cout << "Initialized" << std::endl;
}
static void terminate() {
std::cout << "Terminated" << std::endl;
}
};
However, the declaration is messy since I have to both inherit from and friend my Service class. Is there any way to allow a base class access to protected or private members of a derived class automatically? If not, I may as well ask if there's any better way to write what I've done here.
"Is there any way to allow a base class access to protected or private members of a derived class automatically?"
Base class cannot access private/protected members of derived class formally. In general base classes are designed such a way that they don't need to know anything of derived class. So, if there is a need to access members in derived class from your base class then you should re-consider your design.
EDIT ( As per proposed article by #RSahu ):-
Although there are some scenario where it might be useful to access member functions of derived class from base class. Like when you are sharing objects between two processes.
#include <iostream>
using namespace std;
template<typename T>
class Service {
struct TT: T {
using T::initialize;
using T::terminate;
};
public:
Service() {
if(s_count++ == 0) {
TT::initialize();
}
}
~Service() {
if(--s_count == 0) {
TT::terminate();
}
}
private:
static int s_count;
};
class Test : public Service<Test> {
//friend class Service<Test>;
protected:
static void initialize() {
std::cout << "Initialized" << std::endl;
}
static void terminate() {
std::cout << "Terminated" << std::endl;
}
};
template<typename T>
int Service<T>::s_count = 0;
int main() {
Test t;
}
n.m.'s suggestion of making these methods virtual made me think: it would not work by itself, but it would work if you decouple the service from its management: the initialization doesn't just applies to that particular service instance, it applies to all instances, and perhaps because of that it just shouldn't be part of the service class in the first place.
If you decouple them, you can make a service manager base class, with virtual methods that a derived service manager must implement, like so:
#include <iostream>
class ServiceManager {
template <typename T>
friend class Service;
virtual void initialize() = 0;
virtual void terminate() = 0;
};
template <typename T>
class Service {
public:
Service() {
if (s_count++ == 0) {
s_manager.initialize();
}
}
~Service() {
if (--s_count == 0) {
s_manager.terminate();
}
}
private:
static int s_count;
static ServiceManager &&s_manager;
};
template <typename T>
int Service<T>::s_count = 0;
template <typename T>
ServiceManager &&Service<T>::s_manager = T();
class TestManager : public ServiceManager {
void initialize() {
std::cout << "Initialized" << std::endl;
}
void terminate() {
std::cout << "Terminated" << std::endl;
}
};
class Test : public Service<TestManager> {
};
If your compiler doesn't support this use of && (it's valid C++11, but not valid C++03), you should still be able to easily adapt the code by either making s_manager ServiceManager & and not using a temporary T to initialise it, or just making s_manager have type T. The former is more verbose, the latter allows T implementations that do not derive from ServiceManager.
Let say I've this code with a EnvelopeMultiPoints class template:
#include <iostream>
#include <vector>
class EnvelopeMultiPointsBase
{
// base
};
template<class T>
class EnvelopeMultiPoints : public EnvelopeMultiPointsBase
{
public:
static unsigned int mNumPoints;
EnvelopeMultiPoints() { }
~EnvelopeMultiPoints() { }
void Process() {
std::cout << "process: " << mNumPoints << std::endl;
}
};
class Pitch : public EnvelopeMultiPoints<Pitch> { };
template<typename T>
unsigned int EnvelopeMultiPoints<T>::mNumPoints = 5;
class Container
{
public:
EnvelopeMultiPointsBase *pAssociatedEnvelope;
Container(EnvelopeMultiPointsBase *associatedEnvelope) : pAssociatedEnvelope(associatedEnvelope) { }
~Container() { }
void Process();
private:
};
int main()
{
EnvelopeMultiPoints<Pitch> pitch;
Container container(&pitch);
container.pAssociatedEnvelope->Process();
}
And I want to pass to the Container any kind of "EnvelopeMultiPoints" types (a generic "pointer"), so later I can access to its own method (in my case, Process()).
Does it means that also Container must be templated? (which is huge in my real scenario; lot of works to transform all of its methods in template, translate header/cpp, and such).
Or is there a trick that I'm missing?
In few words: let say that I want to pass to Container EnvelopeMultiPoints<Pitch>, and than execute Process(). Later, I want to pass EnvelopeMultiPoints<Volume> instead, and than execute Process(). And so on. Is there a way to do this without converting also Container to a template?
The technique you need is called dynamic polymorphism
that is implemented in C++ by virtual functions.
Illustrating using your code:
class EnvelopeMultiPointsBase
{
public:
// Abstract base, no actual implementation
virtual void Process() = 0;
};
template<class T>
class EnvelopeMultiPoints : public EnvelopeMultiPointsBase
{
public:
static unsigned int mNumPoints;
EnvelopeMultiPoints() { }
~EnvelopeMultiPoints() { }
// Some specific implementation.
virtual void Process() override
{
std::cout << "process: " << mNumPoints << std::endl;
}
};
class Pitch : public EnvelopeMultiPoints<Pitch>
{
};
To call the Process function of the base class, you have to define it in the base class. You can move the implementation to templated child classes:
class EnvelopeMultiPointsBase
{
private:
virtual void ProcessImpl() = 0;
public:
void Process() {
//potential common code...
ProcessImpl();
//more potential common code...
}
};
template<class T>
class EnvelopeMultiPoints : public EnvelopeMultiPointsBase
{
public:
static unsigned int mNumPoints;
EnvelopeMultiPoints() { }
~EnvelopeMultiPoints() { }
private:
void ProcessImpl() {
std::cout << "process" << std::endl;
}
};
One of the main benefits of virtual in C++ is being able to use the base class (pointer or reference) to call derived methods.
I'm reading up on using CRTP to implement static polymorphism, but I can't understand how to achieve what I've mentioned above using this technique, because I can't declare a function as taking type Base when this requires a template.
It seems to me that what is described in the article could be achieved by simply using function overloading, so I'm sure that there must be more to this technique.
(PS: this exact problem is alluded to in a comment to an answer to this question, but unfortunately no one had replied to it: "What vtables truly provide is using the base class (pointer or reference) to call derived methods. You should show how it is done with CRTP here.")
Here is my minimal code, which gives the error "missing template arguments before ‘&’ token
void Print(Base& Object)".
#include <cstring>
#include <iostream>
template <typename Derived>
struct Base
{
std::string ToStringInterface() { return static_cast<Derived*>(this)->ToString(); }
std::string ToString() { return "This is Base."; }
};
struct Derived : Base<Derived>
{
std::string ToString() { return "This is Derived."; }
};
void Print(Base& Object)
{
std::cout << Object->ToStringInterface() << std::endl;
}
int main()
{
Derived MyDerived;
// This works, but could have been achieved with a function overload.
std::cout << MyDerived.ToStringInterface() << std::endl;
// This does not work.
Print(MyDerived);
}
Thanks to the comments and answers received, I'm posting my implementation, in case it may come in useful to anyone else.
#include <cstring>
#include <iostream>
template <typename Derived>
class Base
{
public:
std::string ToStringInterface()
{
return static_cast<Derived*>(this)->ToString();
}
};
template<>
class Base<void> : public Base<Base<void> >
{
public:
std::string ToString()
{
return "This is Base (default implementation).";
}
};
class Derived : public Base<Derived>
{
public:
std::string ToString()
{
return "This is Derived.";
}
};
template <typename T>
void Print(Base<T>& Object)
{
std::cout << Object.ToStringInterface() << std::endl;
}
int main()
{
int Decision;
std::cout << "Do you want to create an object of type Base (input 0) or Derived (input 1)? ";
std::cin >> Decision;
if (Decision == 0)
{
Base<void> MyBase;
Print(MyBase);
}
else
{
Derived MyDerived;
Print(MyDerived);
}
}
Well, you need to declare print a template function :
template<class T>
void Print(Base<T>& Object)
{
std::cout << Object.ToStringInterface() << std::endl;
}
Sorry, but it CRTP indeed doesn't work that way. The idea is typically to inject some code into the dependency hierarchy, in a way that is very specific to C++. In your example, you could have e.g. an interface that requires the ToStringInterface() function and use CRTP to bind it to an existing class hierarchy's ToString():
class IStringable
{
virtual string ToStringInterface() = 0;
};
class Unchangeable
{
virtual string ToString();
};
template<class Derived>
class UnchangeableToIStringableMixin
{
virtual string ToStringInterface()
{
return static_cast<Derived*>(this)->ToString();
}
};
class StringableUnchangeable:
public Unchangeable, UnchangeableToIStringableMixin<StringableUnchangeable>
{
};
However, if Unchangeable can actually be changed, you wouldn't do something like that. Don't forget to consider the possibility that CRTP just isn't the right tool for what you are doing.
I have the case where I am deriving a class from two different base classes both having a static function with the same name.
To resolve this ambiguity, I tried to use the scope operator - just as I would do for a member function. However This does not compile. Why? Wrong syntax?
I want to call the static function via the derived typename and not directly via base class name. Actually I would like prefer to prevent this case, but I have no idea how to do so.
The error (commented out) in the code below also occurs, when I leave the templates away:
#include <iostream>
template<class TDerived>
class StaticBaseA
{
public:
static void announce()
{
std::cout << "do something" << std::endl;
}
};
template<class TDerived>
class StaticBaseB
{
public:
static void announce()
{
std::cout << "do something else" << std::endl;
}
};
class Derived :
public StaticBaseA<Derived>
, public StaticBaseB<Derived>
{
using StaticBaseA<Derived>::announce;
};
class NonDerived {};
int main(int argc, char* argv[])
{
Derived::announce();
// What I want:
//Derived::StaticBaseB<Derived>::announce(); Error: "Undefined symbol 'StaticBaseB'
// What works, but what I don't want ...
StaticBaseB<Derived>::announce();
// ... because I would like to prevent this (however this is done):
StaticBaseB<NonDerived>::announce();
return 0;
}
Making "announce" protected in StaticBaseA and StaticBaseB might be part-way to doing what you want.
You then could not call StaticBaseB<NonDerived>::announce from main as it would be inaccessible. You could call it from a class derived from StaticBaseB.
In other words:
template<class TDerived>
class StaticBaseA
{
protected:
static void announce()
{
std::cout << "do something" << std::endl;
}
};
template<class TDerived>
class StaticBaseB
{
protected:
static void announce()
{
std::cout << "do something else" << std::endl;
}
};
In Derived you have to promote "announce" to public.
class Derived : public StaticA<Derived>, public StaticB<Derived >
{
public:
using StaticA<Derived>::announce;
};
int main()
{
Derived::announce(); // legal and calls StaticBaseA::announce
NotDerived::announce(); // no such function
StaticBaseA< Derived >::announce(); // not accessible
StaticBaseB< Derived >::announce(); // also not accessible
StaticBaseA< NotDerived >::announce(); // not accessible
StaticBaseB< NotDerived >::announce(); // also not accessible
}
For a container class I'd like to provide an interface with several functions which are grouped into categories, for example:
Data::Get::FirstGetter()
Data::Get::SecondGetter()
Data::Set::FirstSetter()
Data::Set::FirstSetter()
This would allow for something like this:
Data myData;
myData::Set::FirstSetter( stuff );
std::cout << myData::Get::FirstGetter() << std::endl; // -> "stuff"
Obviously the code itself is bogus and I've used the scope operator :: as a potential placeholder for something else (I am aware that you can not create namespaces within a class).
An approach to achieve something like this is demonstrated in the following snippet:
#include <iostream>
struct Foo {
private:
struct aBar {
void IFunc(){
std::cout << "IFunc()" << std::endl;
}
};
public:
void OFunc(){
std::cout << "OFunc()" << std::endl;
}
aBar Bar;
};
int main(){
Foo foo;
foo.OFunc();
foo.Bar.IFunc();
}
However, in order to use this, one must create an instance of each grouping object (in the pseudocode example one instance of Get and another one of Set, in the dummy example one instance of aBar). Is there a way to achieve this functionality in a different way (maybe using the actual scope operator :: to indicate the member that is to be called resides within an inner scope)?
I don't really understand the reason why you want to achieve such a behaviour. However, if you want to achieve something like that you may get inspired by the following (although I won't ever use some code like this in any project, still not seeing one plausible reason):
#include <iostream>
class Interface1
{
protected:
virtual ~Interface1() {}
virtual void DoStuff1() = 0;
};
class Interface2
{
protected:
virtual ~Interface2() {}
virtual void DoStuff2() = 0;
};
class Interface3
{
protected:
virtual ~Interface3() {}
virtual void DoStuff3() = 0;
};
class Container;
class Grouper1
{
public:
static void DoStuff1(Container& arContainer);
static void DoStuff2(Container& arContainer);
};
class Grouper2
{
public:
static void DoStuff3(Container& arContainer);
};
class Container : public Interface1, public Interface2, public Interface3
{
public:
virtual ~Container() {}
private:
friend class Grouper1;
friend class Grouper2;
virtual void DoStuff1() { printf("DoStuff1()\n"); }
virtual void DoStuff2() { printf("DoStuff2()\n"); }
virtual void DoStuff3() { printf("DoStuff3()\n"); }
};
void Grouper1::DoStuff1(Container& arContainer) { arContainer.DoStuff1(); }
void Grouper1::DoStuff2(Container& arContainer) { arContainer.DoStuff2(); }
void Grouper2::DoStuff3(Container& arContainer) { arContainer.DoStuff3(); }
int main(int aArgc, char** aArgv)
{
Container c;
Grouper1::DoStuff1(c);
Grouper1::DoStuff2(c);
Grouper2::DoStuff3(c);
return 0;
}
This way your Container can implement some interfaces and your Groupers provide static functions (grouped) to access those methods (although you need to pass the actual Container, you want to work on). But definitely you won't achieve namespace-like access if you don't provide some helper functions/classes (as Grouper1, Grouper2).