Name für Basisklasse + Typedef gesucht
-
camper schrieb:
Einheitlicher Name, einheitliche Basis für shared_from_this?
Etwas einfallslos: uniform_shared_base und uniform_name?Naja...
Der Name des Typedefs sollte schon "die Basisklasse dieses Controls" zum Ausdruck bringen.
Ich glaube ich werde bei "ControlBase" bleiben (evtl. wäre auch "BaseControl" OK).
Fehlt nur noch der Name für die Klasse selbst.
"StandardControlBase" wäre vielleicht was. Hm.
-
Default, Default, Default, ...

-
hustbaer schrieb:
Es war auf jeden Fall nicht höflich.Etwas als "sinnlos" zu bezeichnen, was man (offensichtlich) nicht verstanden hat, ist nicht höflich. Höflich wäre gewesen nachzufragen.
Nicht nicht verstanden - vergessen. Das ist ein wesentlicher Unterschied.

hustbaer schrieb:
Da du das, in deiner immerwährenden Selbstüberschätzung (aus der die Sicherheit erwächst etwas verstanden zu haben, wenn du es eben nicht verstanden hast), sehr häufig machst, reagiere ich darauf etwas genervt.
Im Nachhinein betrachtet hätte ich wohl auch nicht anders reagiert - ich vergebe dir.
hustbaer schrieb:
Punkt 2 ist weiterhin eine Frage der Konvention, ein absolutes Statemend dazu ist dementsprechend weiterhin Blödsinn.
Und diese Konvention hat sich weitestgehend durchgesetzt.
-
BTW: da das Thema nun schon aufgegriffen wurde: findet ihr die Verwendung einer solchen Basisklasse + typedef darin auch schlecht/fragwürdig?
Man könnte das natürlich auch alles anders lösen, ganz ohne die "Zwischen-Basisklasse", nur gefallen mir alle anderen Lösungen (die mir eingefallen sind) noch weniger.
Speziell was das Thema shared_from_this() angeht.
Immer Casten wo der abgeleitete Type gebraucht wird finde ich nicht gut.
Es in jeder abgeleiteten Klasse zu wiederholen finde ich auch nicht gut.
Bliebe noch die Möglichkeit ein Makro zu verwenden, aber ... naja. Den "Aufruf" des Makros müsste man auch in jeder Klasse wiederholen, und ... hmpf. Gefällt mir also auch nicht so richtig.Das einzige was mich bei der "Zwischen-Basisklasse" stört, ist, dass diverse Tools wie Doxygen sich damit nicht so richtig anfreunden können. Eigentlich sollte die "Zwischen-Basisklasse" in Doxygen Charts gar nicht auftauchen, sondern direkt der "BASE" Typ als Basisklasse. Dazu konnte ich Doxygen aber blöderweise nicht überreden.
-
@314159265358979:
Ja ja, wie du meinst.
-
Zeus schrieb:
Default, Default, Default, ...

Default klingt für mich, im Zusammenhang mit C++, immer nach etwas, was man bekommt wenn man irgendwas nicht angibt.
Default-Ctor (keine Parameter angegeben), Default-Argument (kein Argument angegeben), Default-Implementierung (keine Implementierung angegeben, mit SpecialFunction() = default).
Das passt in dem Fall IMO nicht gut.Standard passt IMO besser. Standard heisst für mich ... naja, dass es eben "Standard" ist, aber man es auch anders machen kann (wenn es gute Gründe dafür gibt).
-
hustbaer schrieb:
Zeus schrieb:
Default, Default, Default, ...

...
Das war ein Joke von einen Java-Programmierer

-
Zeus schrieb:
hustbaer schrieb:
Zeus schrieb:
Default, Default, Default, ...

...
Das war ein Joke von einen Java-Programmierer

Den verstehe ich nicht


-
hustbaer schrieb:
BTW: da das Thema nun schon aufgegriffen wurde: findet ihr die Verwendung einer solchen Basisklasse + typedef darin auch schlecht/fragwürdig?
Es ist immerhin eine weitere Abtraktion, die ich erst lernen muß. Ich hasse Abstraktionen, die sich nicht aus den Begriffen der Programmlogik ergeben.
Wenn ich recht sehe, willst Du nur...class HappyFooControl : public FooControl { public: typedef FooControl Base;//...nur diese kleine Zeile automagisieren using Base::SomeFunction(); virtual void SomeOverride() { Base::SomeOverride(); Whatever(); } };
-
Offtopic for only one, hustbear - a litte pattern:
public interface AbilityOne { void one(); } public interface AbilityTwo { void two(); } public class DefaultOne implements AbilityOne { @Override public void one() { System.out.println("rly i am meaningful"); } } public class DefaultTwo implements AbilityTwo { @Override public void two() { System.out.println("sure i am meaningful"); } } public abstract class AbstractMeaningful implements AbilityOne, AbilityTwo { } public class DefaultMeaningful extends AbstractMeaningful { private AbilityOne one = new DefaultOne(); private AbilityTwo two = new DefaultTwo(); @Override public void one() { one.one(); } @Override public void two() { two.two(); } }
-
hustbaer schrieb:
Bfindet ihr die Verwendung einer solchen Basisklasse + typedef darin auch schlecht/fragwürdig?
Man könnte das natürlich auch alles anders lösen, ganz ohne die "Zwischen-Basisklasse", nur gefallen mir alle anderen Lösungen (die mir eingefallen sind) noch weniger.
Ich find's ok. Nicht optimal, aber man schreibt idR selten eigene Controls, da ist kurze Einarbeitungszeit in Ordnung. Anwesenheit des typedefs ist ok wenn man ohne Nachschlagen/Intellisense sieht, dass eben jenes Parent damit gemeint ist.
Rein aus Interesse: Woran liegt es denn, dass man nicht einfach nur von direkt Control ableiten kann? Oder spezifische Hilfsfunktionen?
hustbaer schrieb:
Speziell was das Thema shared_from_this() angeht.
Das "spezialisieren" von shared_from_this finde ich eine coole Idee, hab ich so noch nicht gesehen.
-
So mal C++

template<class T> class ControlUtility { protected: explicit ControlUtility(T* base_) : base(base_) { } private: T* base; }; class FooControl : public Control, private ControlUtility<FooControl> { public: using ControlUtility<FooControl>::SomeFunction(); virtual void SomeOverride() { ControlUtility<FooControl>::SomeOverride(); Whatever(); } };
-
volkard schrieb:
Wenn ich recht sehe, willst Du nur...
typedef FooControl Base;//...nur diese kleine Zeile automagisierenNicht nur, ich will:
class HappyFooControl : public FooControl { public: // die folgenden 3 zeilen automagisieren typedef FooControl Base; shared_ptr<HappyFooControl> shared_from_this() { return static_pointer_cast<HappyFooControl>(Control::shared_from_this()); } shared_ptr<HappyFooControl const> shared_from_this() const { return static_pointer_cast<HappyFooControl const>(Control::shared_from_this()); } // Control::shared_from_this() statt Base::shared_from_this() hier deswegen, // damit bei tieferen Hierarchien nicht verschachtelt static_pointer_cast() aufgerufen werden muss, // da der Compiler die Aufrufe leider nicht wegoptimieren kann, und Interlocked-Calls teuer sind using Base::SomeFunction(); virtual void PostConstructor() { Base::PostConstructor(); ConnectToEvent(someEvent, &HappyFooControl::FunFunFun, shared_from_this()); } private: void FunFunFun(EventData& eventData); };Hast du nen Vorschlag (ausser die 3 Zeilen in jede Control-Klasse reinzuschreiben)?
volkard schrieb:
Es ist immerhin eine weitere Abtraktion, die ich erst lernen muß. Ich hasse Abstraktionen, die sich nicht aus den Begriffen der Programmlogik ergeben.
Ja, ich normalerweise auch.
-
fdfdg schrieb:
Rein aus Interesse: Woran liegt es denn, dass man nicht einfach nur von direkt Control ableiten kann? Oder spezifische Hilfsfunktionen?
Man kann durchaus direkt ableiten. Nur tu' ich es nicht, weil ich es mit der Zwischenbasisklasse praktischer finde.
Das selbe würde sich mit einem Makro erreichen lassen:
#define CONTROL_STUFF_IMPL(DERIVED, BASE) \ public: \ typedef BASE Base; \ BOOST_STATIC_ASSERT(boost::is_base_and_derived<BASE, DERIVED>::value); \ BOOST_STATIC_ASSERT(boost::is_base_and_derived<Control, DERIVED>::value); \ shared_ptr<DERIVED> shared_from_this() \ { \ return static_pointer_cast<DERIVED>(Control::shared_from_this()); \ } \ shared_ptr<DERIVED const> shared_from_this() const \ { \ return static_pointer_cast<DERIVED const>(Control::shared_from_this()); \ } // end of CONTROL_STUFF_IMPL()Und Verwendung:
class HappyFooControl : public FooControl { CONTROL_STUFF_IMPL(HappyFooControl, FooControl); public: using Base::SomeFunction(); virtual void PostConstructor() { Base::PostConstructor(); ConnectToEvent(someEvent, &HappyFooControl::FunFunFun, shared_from_this()); } private: void FunFunFun(EventData& eventData); };hustbaer schrieb:
Speziell was das Thema shared_from_this() angeht.
Das "spezialisieren" von shared_from_this finde ich eine coole Idee, hab ich so noch nicht gesehen.[/quote]
Ich hab' in einigen Projekten sowas gesehen:class Control : public enable_shared_from_this<Control> { public: template <class DERIVED> shared_ptr<DERIVED> shared_from_this() { BOOST_STATIC_ASSERT(boost::is_base_and_derived<Control, DERIVED>::value); return static_pointer_cast<DERIVED>(enable_shared_from_this<Control>::shared_from_this()); } // + const overload };Dummerweie schützt einen das nicht davor:
void SomeValidControlType::PostConstructor() { Connect(..., shared_from_this<AnotherValidControlType>()); }Natürlich kann man in Control::shared_from_this<T> nen Runtime-Assert über dynamic_cast reinmachen. Bloss in wenig befahrenen Code-Zweigen kanns schonmal passieren, dass der beim Testen nie triggert.
-
class Control { private: shared_ptr<Control> shared_from_control() {//KA, was Control::shared_from_this vorher machte } public: template<typename DERIVED> static shared_ptr<DERIVED> shared_from(DERIVED* d)//Ich benutze den Typ von this { return static_pointer_cast<DERIVED>(d->shared_from_control()); } }; class HappyFooControl : public FooControl { public: typedef FooControl Base;//jetzt nur noch private Bequemlichkeit virtual void PostConstructor() { Base::PostConstructor(); ConnectToEvent(someEvent, &HappyFooControl::FunFunFun, shared_from(this));//eh netterer aufruf, oder? }
-
Hmja, das wäre ne Möglichkeit.
eh netterer aufruf, oder?
Nö, gefällt mir eigentlich nicht so gut.
Hier zieht auch wieder das "zusätzliche Abstraktion" Argument:
shared_from_this()ist die Signatur die die Leute kennen und erwarten, etwas anderes muss man erst wieder lernen/kennen.
Obwohl ich zugeben muss dass es weniger "versteckt" ist als das automagische Vorhandensein vonshared_from_this()mit dem passenden Returntyp.Muss ich mal, wenn ich Musse habe, die Vor- und Nachteile der beiden Varianten gegeneinander abwägen. Das "Doxygen-Problem" wäre dadurch natürlich gelöst, und das fände ich nicht schlecht. Hmmm...

-
shared_from_this() aus boost kannte ich nicht. Schade, daß es dort nicht schon shared_from(this) heißt.
Ich würde trotzdem ungern eine Zwischenklasse in die Vererbungshierarchie einhängen, nur um einen kleinen Trick abzuziehen, der nicht soo wichtig ist. Das Makro wäre ja auch keine Schande.
Also nicht
class HappyFooControl : public ControlProxyEnableSharedFromThis<HappyFooControl, FooControl>wo gemeint ist
class HappyFooControl : public FooControlVielleicht wäre das genehm?
template<typename BASE,typename DERIVED> class ControlMixinEnableSharedFromThis { typedef BASE Base; shared_ptr<DERIVED> shared_from_this() { return static_pointer_cast<DERIVED>(static_cast<DERIVED*>(this)->Control::shared_from_this()); } }; class HappyFooControl : public FooControl, ControlMixinEnableSharedFromThis<HappyFooControl,FooControl> {
-
Auch nicht doof

Wobei... wird das nicht ambiguous? Muss ich morgen ausprobieren.
-
hustbaer schrieb:
Auch nicht doof

Wobei... wird das nicht ambiguous? Muss ich morgen ausprobieren.Es wird ambig.
-
lol, dann kommen wir heute zu einem sehr sehr seltenen Gast, der virtuellen Vererbung. Oder mein Compiler ist nur müde geworden und ist zu erschöpft, mir noch zu widersprechen.
#include <iostream> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> using namespace boost; class Control:virtual public enable_shared_from_this<Control> { }; template<typename DERIVED> struct EnableSharedFromThisControlMixin:virtual public enable_shared_from_this<Control> { shared_ptr<DERIVED> shared_from_this() { return static_pointer_cast<DERIVED>(enable_shared_from_this<Control>::shared_from_this()); } }; class FooControl : public Control { public: void SomeFunction() { } }; class HappyFooControl : public FooControl, public EnableSharedFromThisControlMixin<HappyFooControl> { public: typedef FooControl Base; using Base::SomeFunction; static void test(shared_ptr<HappyFooControl>) { std::cout<<"sphfc\n"; } virtual void PostConstructor() { test(shared_from_this()); } private: void FunFunFun(int& eventData); }; int main() { shared_ptr<HappyFooControl> hfc(new HappyFooControl); hfc->PostConstructor(); }