Brown Bag #3 Return of the C++. Topics Common C++ “Gotchas” Polymorphism Best Practices ...

30
Brown Bag #3 Return of the C++

Transcript of Brown Bag #3 Return of the C++. Topics Common C++ “Gotchas” Polymorphism Best Practices ...

Page 1: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Brown Bag #3Return of the C++

Page 2: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Topics

Common C++ “Gotchas”

Polymorphism

Best Practices

Useful Titbits

Page 3: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Common C++ “Gotchas”

Circular dependencies

Slicing

Rule of Three

Page 4: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Circular Dependencies

Problem:

Two classes that depend on each other

Can’t use #include in both headers

// file: A.h

#include “B.h”class A { B _b; };

// file: B.h

#include "A.h”class B { A _a; };

// file: A.h

class B; class A { B& _b; };

// file: B.h

class A;class B { A& _a; };

Solution:

Use forward declarations!

Use (smart) pointers / references for members

Limit includes in headers (helps compilation)

Page 5: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Rule of Three

If you define one of these, define all three:

Destructor

Copy constructor

Assignment operatorMyClass& MyClass::operator= (const MyClass& other){ if (this != &other) { // Do stuff }

return *this;}

Otherwise implicitly generated

Latter 2 copy all class members

Copies pointers not objects

Want move/swap semantics?

Call base version from derived classes

Rule of Two: RAII destructors

Page 6: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Slicing

Problem:

Loss of derived class functionality

Occurs when derived class copied into base class

Especially when passing by value

void Foo( BaseClass baseParam );

...

DerivedClass myDerived;Foo( myDerived );

Solution:

Pass by reference or pointer!

Avoid concrete base classes

Page 7: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Polymorphism

‘virtual’

Implicit Override

Explicit Override

‘final’

Abstract Classes

Interfaces

Multiple Inheritance

Virtual Class Inheritance

Page 8: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

‘virtual’

Used to declare virtual functions.

Virtual functions can have functionality overwritten in child classes.

class Animal{ virtual int GetNumLegs();};

class Dog : public Animal{ virtual int GetNumLegs();};

class Octopus : public Animal{ virtual int GetNumLegs();};

int Animal::GetNumLegs(){ return 0;}

int Dog::GetNumLegs(){ return 4;}

int Octopus::GetNumLegs(){ return 8;}

Page 9: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Implicit Override

C++ traditionally does not require use of the ‘override’ keyword.

class Parent{ virtual void Foo(int i);};

class Child : public Parent{ virtual void Foo(float i);};

Child::Foo does not override Parent::Foo as they have different signatures.

Compiler will not raise an error over this – this is valid declaration.

Page 10: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Explicit Override

C++11 introduces the ‘override’ keyword to ensure virtual functions are overwritten.

class Parent{ virtual void Foo(int i);};

class Child : public Parent{ virtual void Foo(float i) override;};

If the base class does not contain a virtual function with the same signature, the compiler will throw an error.

Useful to ensure functions are overwritten correctly.

Page 11: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

‘final’

C++11 also introduces the ‘final’ keyword.

This ensures that a virtual function cannot be overwritten in child classes.

class Parent{ virtual void Foo() final;};

class Child : public Parent{ virtual void Foo() override;};

Attempting to override a virtual function declared as final will cause the compiler to throw an error.

Page 12: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Abstract Classes

An abstract class is one which you cannot instantiate.

Contains virtual function(s) which must be overwritten in the child class.

A class is abstract if it contains at least pure virtual function.class Parent{ virtual void Foo() = 0;};

class Child : public Parent{ virtual void Foo();};

Parent parentObject; // ERRORChild childObject; // OK

Page 13: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Interfaces

Similar to an abstract class whose functions are all pure virtual.

Defines certain functionality that a class must implement.

Implementation of functions is individual to each class.

__interface IDancer{ void Dance();};

class Fireman : public IDancer{ virtual void Dance();};

class Butcher : public IDancer{ virtual void Dance();};

Page 14: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Interfaces (cont.)

Objects that implement an interface can be cast to their interface type.

Allows for easy communication between otherwise unrelated object types.

Easier manipulation of objects.std::vector<IDancer> dancers;Fireman fireman;Butcher butcher;

dancers.push_back(fireman);dancers.push_back(butcher);

std::for_each(dancers.begin(), dancers.end(), [](IDancer dancer){ dancer.Dance();});

Page 15: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Multiple Inheritance

Consider the following example:

Animal

Mammal WingedAnimal

Bat

class Animal{ virtual void Eat();};

class Mammal : public Animal{ …};

class WingedAnimal : public Animal{ …};

class Bat : public Mammal, public WingedAnimal{ …};

Page 16: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Multiple Inheritance (cont).

If we call Bat::Eat(), which function do we call?

It is an ambiguous function call.

This is because we have two Animal base classes.

Static cast to Animal is also ambiguous.

Page 17: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Virtual Class Inheritance

We can use the ‘virtual’ keyword when inheriting from a class:

class Animal{ virtual void Eat();};

class Mammal : public virtual Animal{ …};

class WingedAnimal : public virtual Animal{ …};

class Bat : public Mammal, public WingedAnimal{ …};

Page 18: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Virtual Class Inheritance (cont.)

The ‘virtual’ keyword will ensure that when a Bat object is created, the Animal instance used by Mammal and WingedAnimal will be the same.

This will remove any ambiguity from calls to Bat::Eat().

Will also allow direct casting of Bat to Animal.

Page 19: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Best Practices

Const WTF

Const FTW

Preprocessor FTL

Enums FTW

Page 20: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Const WTF

1. const Thing* a = new Thing();2. Thing const * b = new Thing();3. Thing* const c = new Thing();

4. const Thing* const d = new Thing();

1. Pointer to constant object - Pointer cannot change object

2. Same as 1.

3. Constant pointer to object - Pointer itself cannot change

4. All the const -Neither pointe or pointed can change

Page 21: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Const FTW

Prefer pass-by-reference-to-const to pass-by-value (item #20)

Avoids unnecessary constructors/destructor calls

Still guarantee to caller that object won’t be changed

void Foo( const Thing& input );void Foo( Thing const & input );

Thing GetData() const;

const member functions (getters)

void Foo( Thing input );void Foo( Thing input );

Page 22: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Preprocessor FTL

Avoid #define literals

Not type-safe

Not scoped

Use initialized constant instead

#define SuperImportant = 42;#define SuperImportant = 42;const int SuperImportant = 42;

Avoid #define pseudo-functions

Look like function calls, aren’t

Same type/scope problems

Use initialized constant instead

#define MAX(a, b) ((a < b) ? b : a);#define MAX(a, b) ((a < b) ? b : a);

inline int MAX(int a, int b){ return (a < b) ? b : a;}

Page 23: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Enums FTW

struct MyEnum{ enum Enum { MAX };};

enum class MyEnum { MAX};

Nicer and safer than preprocessor definitions

Enum classes/structs (C++ 11)

Old: Wrap Enums in struct

Now type-safe in C++ 11

Page 24: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Useful Titbits

Type Inference

Range-Based For Loop

Singleton Design Pattern

Treat Warnings as Errors

Visual Assist X

Page 25: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Type Inference (decltype)

C++11 introduces ‘decltype’ which can be used to infer the type of an object based on the declared value of another.

Useful in conjunction with ‘auto’ when heavy operator overloading and casting is required.

char Foo();int i = 0;

decltype(i) a; // a is an intdecltype(0) b; // b is an intdecltype(Foo()) c; // c is a char

Page 26: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Ranged-Based For Loop

An easier way to iterate through all the elements in a sequence of objects.

Supported by:

C-style arrays

Initializer lists

Types that implement begin() and end() iterators (STL Containers).

int myArray[6] = {1, 2, 3, 4, 5, 6};int arrayTotal = 0;

for (int &i : myArray){ arrayTotal += i;}

std::cout << “The sum of all values is “ << arrayTotal << “.\n”; // 21

Page 27: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Singleton Pattern

Limit to one class instance

No public constructors

Single static instance

Semi-controversial design pattern

Don’t overuse it

class S{public: static S& getInstance() { static S instance; return instance; }

private: S(S const&);

// Don't implement void operator=(S const&);};

Stolen from: http://stackoverflow.com/questions/1008019/c-singleton-design-pattern

Page 28: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Treat Warnings as Errors

Page 29: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Visual Assist X

Intellisense++

Refactoring

Improved syntax highlighting

Keyboard shortcuts

Jump between header/source

£30 for students

Page 30: Brown Bag #3 Return of the C++. Topics  Common C++ “Gotchas”  Polymorphism  Best Practices  Useful Titbits.

Further Reading Microsoft Developers Network (MSDN)

CPlusPlus.com