Title: CSE 232N: Miscellaneous Coding Practices
1CSE 232N Miscellaneous Coding Practices
- Greg Hackmann
- September 26, 2006
2Strings
- Standard strings in C are actually arrays of
characters - char someString1 This is, someString2
a string - Why this can be a problem
- someString1 someString2 probably doesnt do
what you expect - Remember, strings are arrays and arrays are
pointers! - someString1 someString2 might do what you
expect - Works if and only if both strings point to the
same array in memory - Strings on the stack have a fixed size
- Makes inputting strings a pain
3Solution C string class
- C standard library includes a string class
which manages memory for you - As a bonus , , , and operators do what
you expect
include ltstringgt include ltiostreamgt ... stdst
ring myString(You typed in ),
userString stdcin gtgt userString stdcout ltlt
myString userString ltlt stdendl
4Default Method Parameters
- You can specify that your method doesnt require
all its parameters - In your method declaration, add someValue
after the parameter to give it a default value
int myMethod(int param1, int optionalParam 15,
string optionalString string(a
string)) ... myMethod(1, 20, string(another
string)) myMethod(1, 20) // Same as
myMethod(1, 20, string(a string) myMethod(1)
// Same as myMethod(1, 15, string(a string)
5Default Method Parameters
- Once one parameter has a default value, all the
parameters afterwards must have one too - int myMethod(int required1, int optional1 15,
int optional2 16, int required2) is illegal - The default method parameters go in the
declaration, but not the implementation
int myMethod(int param1, int optionalParam 15,
string optionalString string(a
string)) ... int myMethod(int param1, int
optionalParam, string optionalString)
...
6Inline Methods
- Contrary to what we said in the 1st meeting, you
can combine declaration and implementation
class MyClass public MyClass(int i)
MyClass() private int field1 inline
MyClassMyClass(int i) field1(i)
class MyClass public MyClass(int i)
field1(i) MyClass() private
int field1
7Inline Methods
- So why not use inline methods all the time?
- Inline methods are a hint to the compiler to copy
the code directly into where you called it - i.e., if you call the method at n places in your
code, then you get n copies of the method in your
executable - Inline methods are slightly faster to call, but
make your program larger and slower to compile - As a general rule, inline only very small methods
(e.g., getters and setters)
8Inheritance
class SubClass public SuperClass
public SubClass(int i, int j) private
MyObject field
SubClass(int i, int j) SuperClass(i),
field(j) // Calls constructor //
SuperClassSuperClass(int)
- Put public SuperClass after class
declaration, and call superclass constructor in
initialization list - public dont alter visibility of fields and
methods inherited from SuperClass - protected make all public fields and methods
inherited from SuperClass protected - private make everything inherited from
SuperClass private
9Overriding Methods
class SuperClass ... stdstring
getName() class SubClass public SuperClass
... stdstring getName()
stdstring SuperClassgetName() return
stdstring(SuperClass) stdstring
SubClassgetName() return
stdstring(SubClass)
Note if you want to override a method in a
sub-class, you have to declare it again
10Overriding Methods
- What if your class wants to call the superclasss
implementation of something instead? - Prefix method call with SuperClassName
stdstring SubClassgetName() return
stdstring(SubClass is a subclass of
SuperClassgetName())
11Overriding Methods
SubClass mySubClass SuperClass ref
mySubClass stdcout ltlt mySubClass.name() ltlt
stdendl stdcout ltlt ref.name() ltlt stdendl
lt prints SubClass lt prints SuperClass
- C normally does early binding the method is
chosen based on the reference or pointer type,
not the underlying objects actual type! - mySubClass.getName() is bound to
SubClassgetName() - ref.getName() is bound to SuperClassgetName()
12Virtual Methods
- Methods declared as virtual will be overridden as
expected
class SuperClass ... virtual
SuperClass() virtual stdstring
getName() SubClass mySubClass SuperClass
ref mySubClass stdcout ltlt mySubClass.name()
ltlt stdendl stdcout ltlt ref.name() ltlt
stdendl
lt prints SubClass lt prints SubClass
13Virtual Destructors
- Why declare the destructor as virtual?
- In case anyone does this
class SuperClass ... virtual
SuperClass() virtual stdstring
getName()
SubClass mySubClass new SubClass() ... SuperC
lass ptr mySubClass ... delete ptr //
Without a virtual destructor, this calls
SuperClassSuperClass()
14Why Virtual Methods?
- Virtual methods do late binding program
doesnt pick which method to run until runtime - Each instance of the object maintains a virtual
method table (aka vtable) which indicates which
version of each virtual method to use - Early binding can be done at compile-time, and
can be optimized - Late binding is about 2x - 3x slower than early
binding
15Pure Virtual Methods
- Forces subclass to implement method
- aka Abstract Methods
- Add 0 after method declaration to make it
pure virtual - Abstract class a class with at least one pure
virtual method - Interface a class with only pure virtual methods
class AbstractClass public virtual int
abstractMethod() 0
16Multiple Inheritance
- C objects can inherit from multiple
superclasses simultaneously
class SubClass public SuperClassA, public
SuperClassB public SubClass() virtual
SubClass()
SubClassSubClass() SuperClassA(),
SuperClassB() SubClassSubClass()
17Multiple Inheritance
- If any superclasses share a method with the same
signature, then the subclass must explicitly
override it
class SubClass public SuperClassA, public
SuperClassB ... int someMethod() ..
. int SubClasssomeMethod() return
SuperClassAsomeMethod()
class SuperClassA ... int
someMethod() class SuperClassB ...
int someMethod()
18Throwing Exceptions
- Like most modern OOP languages, C includes
exception throwing and handling - Unlike most modern OOP language, C lets you
throw almost anything as an exception - throw stdexception()
- throw MyObject()
- throw An error occurred
- throw stdstring(An error occurred)
- throw 5
- stdruntime_error is a good base class for
making your own exceptions
Note a char is being thrown here, not a
stdstring
19Throwing Exceptions
- What happens if your constructor throws an
exception? - The destructor is not called!
- Anything you allocated up to that point leaks
- Solutions
- De-allocate before throwing the exception
- Use auto_ptr whenever possible
LeakyConstructorLeakyConstructor()
someField(new SomeObject()) throw This
will leak an object
20Throwing Exceptions
- What happens if your destructor throws an
exception? - Dont do it!
- Why not?
- When an exception is thrown, any objects inscope
are destructed - And if that destructorthrows an exception,then
your program isguaranteed to immed-iately
terminate
try SomeObject obj ... catch(SomeExcept
ion e) // obj is destructed before we
// reach here
21Catching Exceptions
try // Code that might throw an
exception catch(stdexception e) //
Handle stdexception catch(MyObject e)
// Handle MyObject catch(char e) //
Handle char catch(...) // Handle
anything else
As a general rule, catch references to
objects (otherwise youll catch a copy)
... handles anything that none of the
handlers above it caught
22Catching Exceptions
- When writing handlers, catch the most-specific
types first - The first matching handler is picked -- not
necessarily the most specific one - The throw command re-throws the exception
try ... catch(SubClass e) ...
catch(SuperClass e) ...
catch(...) stdcout ltlt Somebody else can
worry about it ltlt stdendl
throw
23Catching Exceptions
- What happens if you dont catch an exception?
- The method immediately terminates and re-throws
the uncaught exception, in the hopes that someone
higher up on the call stack will handle it - If nobody on the call stack has a handler, then
your whole program will terminate - Same rules apply for constructors and
destructors be sure to catch all exceptions
24const
- Prefix a variables type with const to declare
that its a constant (immutable) value - const double PI 3.14159
- const char str I wont change this string
- const stdstring str2(Or this one)
- Also works with references
- const stdstring ref str2
- Note that you can make const references to non-
const variables (const is considered
less-specific than non- const)
25const Pointers
- Constant pointers are a little more complex
- Form 1 const type pointerName
- pointerName is a pointer to an immutable variable
- i.e., the pointer can move around, but you cant
alter whatever you dereference - e.g., const int myArray new int3
- Legal myArray NULL
- Illegal myArray0 5
26const Pointers
- Form 2 type const pointerName
- pointerName is a fixed pointer to a variable
- i.e., the pointer cant move around, but you
alter what you dereference - e.g., int const myArray new int3
- Legal myArray0 5
- Illegal myArray NULL
- Form 3 const type const pointerName
- pointerName is a fixed pointer to an immutable
variable - i.e., you cant change anything
27const Objects
- If you have a const object, then its immutable
you cant invoke any methods which change it - e.g., const stdstring str(A constant string)
- Legal stdcout ltlt str.size() ltlt stdendl
- Illegal str cant be changed
- Also applies to references and pointers to const
objects
28const Methods
- How does C know which methods change the
object, and which dont? - const keyword after method signature promises
that method wont change the object
class MyClass ... int getSomeField()
const // We promise that getSomeField()
// wont mutate the object
29const Correctness
- You cant promote a const type to a non-const
type - This rule includes method parameters
const MyClass myInstance MyClass ref
myInstance // Compiler error
void MyClasssomeMethod(SomeOtherClass i)
... ... MyClass myClass const SomeOtherClass
someOtherClass myClass.someMethod(someOtherClass)
// Compiler error
Should be const SomeOtherClass i
30Copy Constructors
- How does C copy objects?
- C invokes the copy constructor
- Constructor which takes in a const reference to
the same type
class MyClass public MyClass() //
Normal constructor MyClass(const MyClass
other) // Copy constructor ...
31But I Didnt Declare a Copy Constructor!
- If you dont declare a copy constructor, C
provides one for you - Default copy constructor makes a shallow copy
of all of your fields
MyClassMyClass(const MyClass other)
field1(other.field1), field2(other.field2), ...
32Then Why Do I Need a Copy Constructor?
- If your class allocated any memory, files, etc.,
then the default copy constructor will probably
cause problems
MyClass myInstance ...
MyClass myCopy(myInstance) ...
// Copy is destructed here
33Then Why Do I Need a Copy Constructor?
- Solution explicitly declare a copy constructor
which performs a deep copy of pointers, etc.
MyClassMyClass(const MyClass other)
field1(other.field1), field2(new
SomeOtherClass(other.field2))
34Then Why Do I Need a Copy Constructor?
- Its very easy to copy objects without realizing
it - Pass an object to a method
- Return an object from a method
- etc.
- So, always declare a copy constructor if the
default one isnt good enough -- even if you
dont plan on making any copies