Alltagsnotizen eines Softwareentwicklers



Ähnliche Dokumente
Vorkurs C++ Programmierung

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf Seite 1 von 22

Java: Vererbung. Teil 3: super()

Zählen von Objekten einer bestimmten Klasse

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Was meinen die Leute eigentlich mit: Grexit?

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Professionelle Seminare im Bereich MS-Office

Primzahlen und RSA-Verschlüsselung

Software Engineering Klassendiagramme Assoziationen

Objektbasierte Entwicklung

Ordner Berechtigung vergeben Zugriffsrechte unter Windows einrichten

Fachdidaktik der Informatik Jörg Depner, Kathrin Gaißer

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Grundlagen von Python

SEP 114. Design by Contract

Monatstreff für Menschen ab 50 Temporäre Dateien / Browserverlauf löschen / Cookies

Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken.

Anleitung über den Umgang mit Schildern

C A R L V O N O S S I E T Z K Y. Boost C++ Libraries. Johannes Diemke. Department of Computer Science Learning and Cognitive Systems

Software Engineering Interaktionsdiagramme

IMAP Backup. Das Programm zum Sichern, Synchronisieren, Rücksichern und ansehen von gesicherten Mails. Hersteller: malu-soft

Objektorientierte Programmierung

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

INDEX. Öffentliche Ordner erstellen Seite 2. Offline verfügbar einrichten Seite 3. Berechtigungen setzen Seite 7. Öffentliche Ordner Offline

Qt-Projekte mit Visual Studio 2005

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005

Leichte-Sprache-Bilder

1 Vom Problem zum Programm

Ziel, Inhalt. Programmieren in C++ Wir lernen wie man Funktionen oder Klassen einmal schreibt, so dass sie für verschiedene Datentypen verwendbar sind

Kurzanleitung. MEYTON Aufbau einer Internetverbindung. 1 Von 11

Einführung in die Java- Programmierung

Windows XP Jugendschutz einrichten. Monika Pross Molberger PC-Kurse

Erstellen einer digitalen Signatur für Adobe-Formulare

Erklärung zu den Internet-Seiten von

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank

Arbeiten mit UMLed und Delphi

Objektorientierte Programmierung mit C++ Zusammenfassung der wichtigsten Topics rund um die objektorientierte Programmierung mit C++11

Erstellen von x-y-diagrammen in OpenOffice.calc

Die Post hat eine Umfrage gemacht

Java Kurs für Anfänger Einheit 5 Methoden

Animationen erstellen

Informationsblatt Induktionsbeweis

Inkrementelles Backup

Tragen Sie bitte im Anmeldefeld die Daten ein, die Sie von uns erhalten haben.

Sich einen eigenen Blog anzulegen, ist gar nicht so schwer. Es gibt verschiedene Anbieter. ist einer davon.

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom b

Herstellen von Symbolen mit Corel Draw ab Version 9

Anmeldung und Zugang zum Webinar des Deutschen Bibliotheksverbandes e.v. (dbv)

Einführung in die Java- Programmierung

Guide DynDNS und Portforwarding

5 DATEN Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

Urlaubsregel in David

Updatehinweise für die Version forma 5.5.5

Folge 19 - Bäume Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12

Kurzanleitung zu. von Daniel Jettka

Seite Wo finde ich die Landingpage Auswahl? Seite Wie aktiviere ich eine Landingpage? Seite

Der Kalender im ipad

teischl.com Software Design & Services e.u. office@teischl.com

Installation und Inbetriebnahme von Microsoft Visual C Express

Speicher in der Cloud

Programmieren in Java

1 topologisches Sortieren

Reporting Services und SharePoint 2010 Teil 1

Programmierkurs Java

Alle gehören dazu. Vorwort

SUCHMASCHINENOPTIMIERUNG FÜR DEN INTERNETAUFTRITT

Einrichtung von VPN-Verbindungen unter Windows NT

Das Leitbild vom Verein WIR

Also heißt es einmal mehr, immer eine eigene Meinungen bilden, nicht beeinflussen lassen, niemals von anderen irgend eine Meinung aufdrängen lassen.

Anleitung zur Daten zur Datensicherung und Datenrücksicherung. Datensicherung

SICHERN DER FAVORITEN

infach Geld FBV Ihr Weg zum finanzellen Erfolg Florian Mock

Inhaltsverzeichnis U M S T E L L U N G A U F O F F I C E 3 6 5

Das RSA-Verschlüsselungsverfahren 1 Christian Vollmer

.NET Code schützen. Projekt.NET. Version 1.0

Inhalt. 1 Einleitung AUTOMATISCHE DATENSICHERUNG AUF EINEN CLOUDSPEICHER

26. November EFS Übung. Ziele. Zwei Administrator Benutzer erstellen (adm_bill, adm_peter) 2. Mit adm_bill eine Text Datei verschlüsseln

PowerPoint vertonen. by H.Schönbauer 1

Durchführung der Datenübernahme nach Reisekosten 2011

Anmeldung und Zugang zum Webinar des Deutschen Bibliotheksverbandes e.v. (dbv)

Client-Server-Beziehungen

Impulse Inklusion Selbst-bestimmtes Wohnen und Nachbarschaft

Excel Funktionen durch eigene Funktionen erweitern.

Die neue Aufgabe von der Monitoring-Stelle. Das ist die Monitoring-Stelle:

Partitionieren in Vista und Windows 7/8

Fax einrichten auf Windows XP-PC

Schnellstart - Checkliste

Round Table 60: 859 Pakete für den Weihnachtskonvoi

Was ist Sozial-Raum-Orientierung?

Objektorientierte Programmierung

Delegatesund Ereignisse

Fachbericht zum Thema: Anforderungen an ein Datenbanksystem

SharePoint Demonstration

FORUM HANDREICHUNG (STAND: AUGUST 2013)

Beschreibung Regeln z.b. Abwesenheitsmeldung und Weiterleitung

Eva Douma: Die Vorteile und Nachteile der Ökonomisierung in der Sozialen Arbeit

Datei Erweiterungen Anzeigen!

Transkript:

Alltagsnotizen eines Softwareentwicklers Entkoppeln von Objekten durch Callbacks mit c++-interfaces oder boost.function und boost.bind Tags: c++, entkoppeln, objekt, oop, callback, boost.bind, boost.function, design Daniel Geschka 2010/11/09

1 Szenario: A besitzt B, kein Rückruf Eine Klasse A besitzt über Komposition eine Instanz einer Klasse B. A ruft Methoden von B auf. B weis nichts von A.A besitzt B (s. Beispiel) oder nutzt B via Assoziation. // Datei B.h: class B void g()... ; class A void f()b_.g(); B b_; ; // Datei main.cpp: A a; a.f(); Soweit alles ok. - 2 / 9 -

2 Szenario: B kennt A für Rückruf Erweiterung der Anforderung: B muss nun zusätzlich A benachrichtigen, bzw. eine oder mehrere Methoden von A aufrufen. Lösungsvorschlag: B kriegt einen Zeiger oder eine Referenz auf A: // Datei B.h: class B B(A& a):a_(a) void g() a_.f2(); A& a_; ; class A A():b_(*this) void f() b_.g(); void f2() B b_; ; // Datei main.cpp: A a; a.f(); - 3 / 9 -

Hier gibt es jetzt mehrere Probleme: Compiler-Fehler wegen Cross Includes: A.h inkludiert B.h. In B.h wird auf A verwiesen, was aber noch nicht bekannt ist (Compiler bricht mit Fehler ab). Lösung: Vorwärtsdeklaration von A in B.h. Was hier im Beispiel noch einfach geht, kann in der Praxis mit mehreren sich gegenseitig inkludierenden Headern / sich gegenseitig verwendenden Klassen sehr haarig werden. B, als die im Besitzverhältnis untergeordnete Klasse, weis viel mehr über A, als sie eigentlich wissen müsste, z.b. alle öffentlichen member von A. Änderungen an A führen auch zum Neu-Übersetzen von B. Im Beispiel noch überschaubar, kann das in echtem Code mit vielen Dateien sehr lange dauern, wenn über gegenseitiges Inkludieren und unnötige Komposition und Assoziation viele Klassen und Header oft dann auch ungewollt, bzw. eine Zeit lang unbemerkt indirekt miteinander verzahnt sind, womöglich auch noch über Modul-grenzen oder sogar Paket-Grenzen hinweg (Übersetzungszeiten von 10 Minuten+ fürs ganze Projekt). Klasse B kann nur von Klasse A verwendent werden. Oder man braucht einen A-Dummy nur, um von B eine Instanz anlegen zu können. Die Klassen A und B sind hier unnötig miteinander verzahnt. Vor allem B ist unnötig von A abhängig. 3 Szenario: Rückruf B nach A mit Interface Eigentlich würde es reichen, wenn A B kennt und B nur eine Funktion kennt, die sie auf, bzw. zurückrufen (Callback) kann. Eine mögliche Lösung ist hier, das B ein Callback-Interface definiert und vom Client (hier A) einen Zeiger oder eine Referenz übergeben kriegt, den B für den Callback benutzen kann: // Datei B.h: class B struct I virtual void f2()=0; ; B(I& i):i_(i) void g()... // Was arbeiten... i_.f2(); // Nachricht an i_ schicken/zurückrufen. I& i_; ; - 4 / 9 -

class A : public B::I A():b_(this) // b_ Zeiger auf selbst mitgeben (wir erfüllen B::I) virtual void f2()... // Der Callback, s. B::I void f()... b_.g(); // b_ benutzen B b_; ; // Datei main.cpp: A a; a.f(); Diese Lösung hat viele Vorteile: Der Cross-Include Compiler-Fehler kann so gar nicht auftauchen. B als untergeordente Klasse kennt A nicht. B weis nicht einmal, dass A hinter dem Interface steht. B muss insbesondere A.h nicht inkludieren. Ändert sich A, muss B nicht neu übersetzt werden. - 5 / 9 -

B kann nun auch von anderen Klassen genutzt werden. Das A von B::I erbt ist nicht schädlich, da es eine reine Schnittstellen-Vererbung ist. Insbesondere ändert diese nicht das Verhalten von A, wie es bei richtiger Vererbung von einer Basiklasse sein kann, wenn sich das Verhalten der Basiklasse ändert (Seiteneffekte!). 4 Szenario: Rückruf B nach A mit boost.function & boost.bind Eine andere elegante Möglichkeit besteht im Verwenden von Delegates. In c++ sind diese u.a. realisierbar mit Hilfe von boost::function (Funktionszeiger-Objekte) und boost::bind (festlegen von Methode, Instanz und Reihenfolge der Argumentübergabe beim verzögerten Funktionsaufruf). Der Effekt ist bei dieser Lösung der gleiche: B ist von A entkoppelt: // Datei B.h: #include <boost/function.hpp> class B // Übergabe eines Funktionszeigers im Konstruktor B(const boost::function<void()>& fn):fn_(fn) void g() fn_();// Aufruf mit operator(), hier ohne Rückgabewerte und Argumente boost::function<void()> fn_; ; #include <boost/bind.hpp> class A // Initialisieren von B b_ mit Übergabe des Funktionszeigers für den Callback A():b_(boost::bind(&A::f2,this)) virtual void f2()... void f() b_.g(); void f2()... // Die Callback-Funktion für B b_. B b_; ; // Datei main.cpp: A a; // Erzeugen von A a. a.f(); // a benutzt hier B b_, s. oben Alle Vorteile der Interface-Lösung gellten auch hier. Ein Interface existiert jedoch nicht. B kennt von seinem Client (hier der Klasse A) nur die Signatur der (Member-)Funktion, die B als Callback aufrufen soll. Mehr Entkoppelung geht wohl nicht. - 6 / 9 -

5 Include-Abhängigkeiten nach oben terminieren A.h ist von B.h abhängig. Ändert sich an B.h etwas, hat sich (include!) auch A.h geändert. Weitere Header, die A.h inkludiert haben, sind nun ebenfalls geändert Alle Dateien, die Header inkludieren, die ihrerseits A.h inkludiert haben sind nun auch geändert, usw.. Ändert sich also ein zentraler Header, wird daraus ruck zuck ein Neuübersetzen des ganzen Projektes. Auf geht s : #include <boost/bind.hpp> // Forwärtsdeklaration von B class B; class A A(); virtual ~A(); virtual void f2()... void f() b_->g(); void f2()... // Die Callback-Funktion für B b_. B* b_; ; // Datei A.cpp A::A() b_=new B(boost::bind(&A::f2,this)); - 7 / 9 -

A::~A() delete b_; B.h wird in A.h nun nicht mehr inkludiert. B wird über Vorwärtsdeklaration in A.h bekannt gemacht. Aus dem Member B b_ wurde ein Zeiger B* b_. Der Compiler benötigt zum Analysieren von A.h nicht die exakte Deklaration von B, wenn b_ ein Zeiger auf B ist. Es reicht ihm zu wissen, dass er für B* 4 Byte in A reservieren muss (für Zeiger unabhängig vom Typ immer gleich gross). In A.cpp wird nun B.h inkludiert. Der Konstruktor von A alloziert b_ auf dem Heap, ~A() dealloziert b_ wieder. Der Vorteil der Lösung: A.h ist nicht mehr von B.h abhängig. Ändert sich B.h muss nun nur noch A.cpp neu übersetzt werden. Die Kette der Include-Abhängigkeiten nach oben wurde durchbrochen 1 6 Weitere Beispiele zu boost.function & boost.bind Hier noch einige Beispiele für Callback-Methoden und freie Funktionen, die auch Argumente und Rückgabewerte haben: // Datei main.cpp #include <boost/function.hpp> #include <boost/bind.hpp> #include <string> // Für Methoden Callbacks struct X int f0()... int f1(double arg1)... std::string f2(double arg1, int arg2)... ; // Für Callback einer freien Funktion void foo(int arg1, double arg2, std::string arg3)... // Zum testen von member pointer functions: instanz von X x X x; // Beispiel: Rückgabewert, keine Argumente boost::function<int()> xf0(boost::bind(&x::f0,&x)); int result = xf0(); // return + 1 arg boost::function<int(double)> xf1(boost::bind(&x::f1,&x,_1)); int result = xf1(0.42); // return + 2 arg boost::function<std::string(double,int)> xf2(boost::bind(&x::f2,&x,_1,_2)); std::string result = xf2(0.43,4711); 1 In diesem Zusammenhang lohnt auch ein Blick auf die Klassen boost shared_ptr, bzw. scoped_ptr. - 8 / 9 -

// Beispiel für einen Callback/verzögerten Funktionsaufruf auf eine freie Funktion boost::function<void(int,double,std::string)> f(boost::bind(&foo,_1,_2,_3)); f(4711,0.42, hello world ); - 9 / 9 -