- Files:
se/visitor
- Has a cyclic include and won't compile
- An include creates a compilation dependency
- Often, a forward declaration of a class is all we need (rather than the include)
class XYZ; // you are telling the compiler to trust that class XYZ is getting compiled
- Whenever possible, prefer forward declaration to include:
- reduces compilation dependencies and reduce circular dependencies
- reduce compile time
- reduces frequency of compilation for a file
File: a.h
class A {
};
File: b.h
#include "a.h"
class B : public A {
};
File: c.h
#include "a.h"
class C {
A a;
};
File: d.h
class A;
class D {
A *ptrA;
};
File: d.cc
#include "a.h"
void D::foo() {
ptrA->someMethod();
}
File: e.h
class A;
class E {
A f(A x);
};
File: e.cc
A E::f(A x) {
}
File: window.h
#include <xlib/x11.h>
class XWindow {
Display *d;
Window w;
public:
void draw();
};
File: client.cc
#include "window.h"
myXWindow->draw() {
}
client.cc
has to recompile even if private members in window.h change
- Take the private implementation out of window.h
File: XWindowImpl.h
struct XWindowImpl {
Display *d;
WIndow w;
};
File: window.h
struct XWindowImpl;
class XWindow {
XWindowImpl *pImpl;
public:
void draw();
};
File: window.cc
#include "xwindowimpl.h"
#include "window.h"
XWindow::XWindow() :
pImpl{new XWindowImpl()} {
pImpl->d = ...;
}
- If private implementation changes, window.h and therefor client.cc are not affected
- In UML:
XWwindow |
---|
◆ | ↓
XWindowImpl |
---|
XWwindow |
---|
◆ | ↓
XWindowImpl |
---|
- XWindowImpl will have bunch of implementations
-
Coupling: degree to which modules/classes interact with each other
- low coupling: interaction through a public interface - preferred
- high coupling: interaction through a public implementation
-
Cohesion: how related are things within a module
- low cohesion: loosely connected, such as
<utility>
which has loads of unrelated things - high cohesion: module/class achieves exactly a single task - preferred
- low cohesion: loosely connected, such as
class ChessBoard {
void foo() {
cout << "Your move";
}
};
ChessBoard
is now coupled withstdout
- Slightly better would be to use an
ostream
variable ChessBoard
class has 2 responsibilities: game state, communication- Violates single responsibility principle
- It would be better to have a separate communication class
- Multiple opinions on implementation
Controller
tells theModel
something has changed, theModel
then notifies theView
which then queries from theModel
Controller
tells theModel
something has changed, theModel
then updates theController
and theController
notifies theView
void f() {
MyClass *p = new MyClass();
MyClass c;
g(); // if g() throws an exception, the next line won't get hit and p will leak
delete p;
}