In my application I have a class for which I need to keep a set of interfaces delivered by the application.
Since the class itself doesn't know all the possible interfaces, it can't simply keep one data member for every interface. Instead, it should keep a vector of interfaces.
In practice this means that I define one 'generic' interface (IGeneric) of which all the more specific interfaces inherit. That way, I can easily keep a vector with all the interfaces (in the code hereafter I replaced the actual interface names by some dummy names; in my application the names are much more meaningful):
#include <vector>
#include <windows.h>
class IGeneric
{
public:
virtual ~IGeneric() {}
};
class IFirst : public IGeneric {public: virtual void one() = 0;};
class ISecond : public IGeneric {public: virtual void two() = 0;};
class IThird : public IGeneric {public: virtual void three() = 0;};
class IFourth : public IGeneric {public: virtual void four() = 0;};
typedef std::vector<IGeneric *> GenericContainer;
To install the interfaces, other modules (which really know all the interfaces), provide functions to install the interfaces. They could be something like this:
void installFirst (GenericContainer &bc, IFirst &b) { bc.push_back(&b); }
void installSecond (GenericContainer &bc, ISecond &b) { bc.push_back(&b); }
void installThird (GenericContainer &bc, IThird &b) { bc.push_back(&b); }
void installFourth (GenericContainer &bc, IFourth &b) { bc.push_back(&b); }
In practive, applications will write classes that implement multiple of these interfaces, like this:
class DoAll : public IFirst, public ISecond, public IThird, public IFourth
{
public:
virtual void one() {}
virtual void two() {}
virtual void three() {}
virtual void four() {}
DoAll(int i) : m_i(i) {}
private:
int m_i;
};
Installing this implementation is now really easy. This is the main routine from my example:
int main()
{
GenericContainer gc;
DoAll all (123);
installFirst(gc,all);
installSecond(gc,all);
installThird(gc,all);
installFourth(gc,all);
DebugBreak();
}
At the breakpoint, I now investigate the contents of the vector in the debugger. It looks like this:
As you can see, it shows that the implementation of the interfaces is DoAll (in all 4 cases), and it even shows as which interface (IFirst, ISecond, ...) DoAll has been installed in the vector.
Problem is that the debugger doesn't seem to be able to show the contents of the most derived class (DoAll). It show the datamember m_i, but it is unable to show the value of m_i.
Only if I explicitly take the first interface address, and cast it to "DoAll *", I can correctly see the contents:
I compile and link using the following commands:
cl /c /EHsc /GR /Zi /Od test.cpp
link /debug test.obj
Is this a bug in Visual Studio 2010 or am I missing something?
EDIT:
If I use single inheritance, like in this class:
class DoFirst : public IFirst
{
public:
virtual void one() {}
DoFirst(int i) : m_i(i) {}
private:
int m_i;
};
And install it in the vector like this:
DoFirst f (456);
installFirst (gc,f);
The debugger shows me the correct values and it also immediately shows the most derived class:
In vector you are holding pointers to IGeneric. IGeneric does not have any clue about m_i, which is member of DoAll. We might even say that there actually is a bug, because the debugger is showing {m_i = ???}, but it should not.
Related
I`m trying to implement something like this using C++11.
class Proto{
public:
virtual void fu() = 0;
};
class Impl: public Proto{
public:
void fu();
};
void Impl::fu(){
LOG_INFO("im fu");
}
class Inv{
public:
void useFu(void (Proto::*)());
};
void Inv::useFu(void (Proto::*fu)()){
//fu();
};
void main(){
Impl impl;
Inv inv;
//inv.useFu(impl.fu);
}
useFu(void (Proto::*)()) must be declared in this way because, fu() uses some specific to Proto functionality's
I have two places were things going wrong.
First is fu() call itself and second how to pass fu as parameter inv.useFu(impl.fu).
Edit after bipll answer
The suggested usage of inv.useFu() solves the second problem of my question.
inv.useFu(static_cast<void (Proto::*)(void)>(&Impl::fu));
But I still need to call fu as a pointer to member function;
The way your useFu is declared now, it should be called as
inv.useFu(static_cast<void (Proto::*)(void)>(&Impl::fu));
But I guess that's not what you wanted. It should rather be
template<class F> void useFu(F &&f) { std::invoke(std::forward<F>(f)); }
or simply
void useFu(std::function<void()> f) { std::invoke(std::move(f)); }
and called as
useFu([&]{ impl.fu(); });
(Rather than using a lambda you can bind the method to the object with std::bind in the latter call but almost nobody ever does that.)
In this blog post about dependency injection in C++, the author explain a hybrid approach that uses both templates and interfaces as follows:
ICar.h (publicly visible):
#pragma once
struct ICar
{
virtual void Drive() = 0;
virtual ~ICar() = default;
};
std::unique_ptr<ICar> MakeV8Car();
std::unique_ptr<ICar> MakeV6Car();
Car.h (internal):
#pragma once
#include "ICar.h"
template <typename TEngine>
class Car : public ICar
{
public:
void Drive() override
{
m_engine.Start();
// drive
m_engine.Stop();
}
private:
TEngine m_engine;
};
Car.cpp:
#include "Car.h"
#include "V8Engine.h"
#include "V6Engine.h"
std::unique_ptr<ICar> MakeV8Car()
{
return std::make_unique<Car<V8Engine>>();
}
std::unique_ptr<ICar> MakeV6Car();
{
return std::make_unique<Car<V6Engine>>();
}
All of which makes good sense to me, except for the internal part. Let's assume I've created a shared object from the above.
How is Car.h private in the context of this shared object?
I've read on the meaning of a private header in the answer which states:
Keep your data in MyClassPrivate and distribute MyClass.h.
Presumably meaning to not distribute MyClass_p.h, but how does one avoid distributing a header file and still have the .so work?
I am trying to replace Poco::AutoPtr with some alternative in boost. Here is what I have discovered so far:
What I have: below classess are being used with Poco::AutoPtr. They need to implement reference counted method with implementing duplicate() and release() methods.
I am using above referece_counted.h and Poco::AutoPtr in a complex class hierarchy with multiple inheritance and c++ diamond problems.
A simplified version of classes would look something like this
class A : virtual public ReferenceCounted
{
...
}
class B : public A
{
...
}
class C : public A
{
...
}
class D : public A, B
{
...
}
and the list goes on for few more level deep. I know that this needs to be refactored with a simplified hierarchy but I wanna remove Poco::AutoPtr first with proper replacement in boost:
What I have found so far:
I have found that boost::intrusive_ptr is the closest smart pointer that can be a good replacement of Poco::AutoPtr.
I am however not able to implement the proper solution with this because the intrusive_ptr requires intrusive_ptr_add_ref and intrusive_ptr_release methods created specifically for each class with which I need to use the pointer. I tried using templates but still not having proper solution at hand.
Also one more issue is that I need to typecast from base to derived class many times.
is intrusive_ptr is the correct smart pointer for this usage ? and if yes.. can anybody give me suggestion regarding how to use the same ?
I am however not able to implement the proper solution with this
because the intrusive_ptr requires intrusive_ptr_add_ref and
intrusive_ptr_release methods created specifically for each class with
which I need to use the pointer.
No-no. It is should not be hard. As Boost documentation says:
On compilers that support argument-dependent lookup,
intrusive_ptr_add_ref and intrusive_ptr_release should be defined in
the namespace that corresponds to their parameter; otherwise, the
definitions need to go in namespace boost.
Try this: main.cpp (built ok with "g++ main.cpp -o main -lboost_system")
#include <boost/intrusive_ptr.hpp>
class MyObject
{
public:
void duplicate(){
// ...
}
void release(){
// ...
}
};
namespace boost {
template <class T>
void intrusive_ptr_add_ref( T * po ) {
po->duplicate(); // your internal realization
}
template <class T>
void intrusive_ptr_release( T * po ) {
po->release();
}
}
int main(int argc, char **argv)
{
// ...
boost::intrusive_ptr<MyObject> ptr( new MyObject );
boost::intrusive_ptr<MyObject> ptr2 = ptr; // should work
}
I recently started using C++/Cli for wrapping purposes.
Now I'm at a point where I've to know more about the internals.
Consider the following code:
Header file (ignoring .NET namespaces for this example):
public ref class BaseyClass
{
protected:
delegate void TestMethodDelegate(); // TestMethod delegate
BaseyClass(); // constructor
virtual void TestMethod(); // member: method
GCHandle _testMethodHandle; // member: method handle
};
CPP file (ignoring .NET namespaces for this example):
BaseyClass::BaseyClass()
{
_testMethodHandle
= GCHandle::Alloc(
gcnew TestMethodDelegate(this, &BaseyClass::TestMethod));
}
void TestMethod()
{
}
Eventually this class will be used as base class (for a DerivedClass) later and the method "TestMethod()" gets overridden and called from unmanaged code through the delegate pointer.
Now the question: Which method will be referenced by the delegate?
BaseyClass::TestMethod();
or
DerivedClass::TestMethod();
Personally I think the "BaseyClass::TestMethod()" will be referenced by the delegate because even when it's overridden, the delegate points to the (base-)address of BaseyClass. Hence a DerivedClass cannot override the "TestMethod" and use the delegate from BaseyClass.
I just want to be sure. Thanks for your comments and enlightment.
The delegate will be a reference to the derived class's TestMethod. Even though you're passing &BaseyClass::TestMethod, that's a virtual method, you're also passing this, which is the derived type, and both of those are taken into account when the delegate is created.
Other notes:
TestMethodDelegate doesn't need to be inside the class definition. The more standard way is to have the delegate outside of the class, just in the namespace. (Or use the existing built-in one, Action.)
You don't need to GCHandle::Alloc (I assume that's what you meant by Allow). Instead, declare _testMethodHandle as TestMethodDelegate^ (or Action^). In general, you shouldn't need to deal with GCHandle unless you're interfacing with unmanaged code, and this code is all managed.
Here's my test code:
public ref class BaseyClass
{
public:
BaseyClass() { this->_testMethodHandle = gcnew Action(this, &BaseyClass::TestMethod); }
virtual void TestMethod() { Debug::WriteLine("BaseyClass::TestMethod"); }
Action^ _testMethodHandle;
};
public ref class DerivedClass : BaseyClass
{
public:
virtual void TestMethod() override { Debug::WriteLine("DerivedClass::TestMethod"); }
};
int main(array<System::String ^> ^args)
{
BaseyClass^ base = gcnew DerivedClass();
base->_testMethodHandle();
return 0;
}
Output:
DerivedClass::TestMethod
I'm going nuts trying to find the problem here. I have a main window, and a form type window made in Qt. I'm using the Visual Studio 2010 addon. For some reason, my SLOT is never called in the main window; however, the signal appears to be emitted.
Here's what I've done:
This is the form:
class ScalerValuesWindow : public QWidget
{
Q_OBJECT
private:
Ui::ScalerValuesWindow ui;
// Variables
std::vector<int> scalerValues;
public slots:
void storeScalerValues();
signals:
void ScalerValues(std::vector<int>);
public:
ScalerValuesWindow(QWidget *parent = 0);
};
void ScalerValuesWindow::storeScalerValues()
{
emit ScalerValues(scalerValues);
hide();
}
Then here's my main window connection line in my constructor:
scalerValuesWindow = new ScalerValuesWindow;
connect(scalerValuesWindow, SIGNAL(ScalerValues(std::vector<int>)), this, SLOT(RetrieveScalerValues(std::vector<int>)));
This is in my main window's class declaration:
public slots:
void RetrieveScalerValues(vector<int> scalerValues);
And this is the slot:
void RelayduinoGuiThreading::RetrieveScalerValues(vector<int> scalerVals)
{
scalerValues = scalerVals;
}
I have Q_OBJECT declared in both. I have no idea what could be causing this.
Any advice would be greatly appreciated.
You must define your slot as:
public slots:
void RetrieveScalerValues(std::vector<int> scalerValues);
^^^
(Inspect the generated moc file to see exactly what signal/slot signatures are being generated.)
Don't use using namespace std; in your headers, that's bad practice anyway (pulls in that huge namespace into all the users of that header, which is impolite).