Lecture 8

make

  • builds main

    • what does main depend on?

      • recursively build dependencies - if necessary

      • then build main - if necessary

  • How does make decide it is necessary?

    • checks timestamps (eg. ls -l)

    • if target is older than its dependencies (based on last modified time), it is rebuilt

      • eg. vec.cc changes

      • it is newer than vec.o

      • rebuild vec.o

        • newer than main (executable)

        • rebuild main

make clean

  • full rebuild

Generalize with variables

This file is in repository (example3 Makefile):

cxx = g++ // compiler's name
CXXFLAGS = -std=C++14   -Wall // compiler options
OBJECTS = main.o vec.o
EXEC = main

${EXEC}: ${OBJECTS}
  ${CXX} ${CXXFLAGS} ${OBJECTS} -o ${EXEC}
  • main.o: main.cc vec.h

  • vec.o: vec.cc vec.h

Biggest problem with writing makefiles

  • writing dependencies and keeping them up to date

  • can ge help from g++: g++ -MMD -c vec.cc

    • creates vec.o and vec.d

Vec.d: vec.o: vec.cc vec.h

  • Now just include this in the Makefile

To get this file, edit Makefile in repository

cxx = g++ // compiler's name 
CXXFLAGS = -std=C++14 -Wall -MMD -g
OBJECTS = main.o vec.o 
DEPENDS = ${OBJECTS:o=.d}
EXEC = main 
${EXEC}: ${OBJECTS} 
  ${CXX} ${CXXFLAGS} ${OBJECTS} -o ${EXEC}
- include ${DEPENDS}

What if we want a module to provide a global variable?

Wrong way to do it:

// File: abc.h
int globalNum; // declaration and definition
  • Every file that includes abc.h defines a separate globalNum - program will not link

Solution: put variable in .cc file

// File: abc.cc
int globalNum; // definition
// File: abc.h
extern int globalNum; // declaration, but not a definition

Suppose we write a linear algebra module - code found in separate/example3

  • Does not compile because #include "vec.h" is included twice in main.cc, and struct vec cannot be defined twice

  • Need to prevent files from being included more than once

Solution: #include guard

// File: vec.h
#ifndef VEC_H
#define VEC_H
... // file contents
#endif
  • First time vec.h is included - symbol VEC_H is not defined, so file is included

  • Subsequently, VEC_H is defined, so contents of vec.h are suppressed

  • Always

    • put #include guards in .h files

  • Never

    • put using namespace std; in .h files

      • the usage directive will be forced upon any client that includes the file

      • always say std::cin, std::string, etc. in headers

    • compile .h files (these are compiled by being included .cc files)

Classes

  • Can put functions inside of structs eg.

// File: student.h

struct Student {
  int assns, m+, final;
  float grade();
};
// File: student.cc

#include "student.h"

// Wrong way:
float grade(); // Compiler thinks you are writing a whole new function called grade(), not one connected to struct Student

// Correct way:
float Student::grade() {
  return assns*0.4 + mt*0.2 + final*0.4;
}

Class: structure type that can have functions Object: an instance of a class Member function/Method: function inside class (eg. grade() in Student) Scope resolution operator: :: eg. C::f means f is in the context of the class (or namespace) C. :: like ., where LHS is a class (or namespace), not an object

// client:

// Student is the class
// s{60,70,80} is the object
Student s{60,70,80},
cout << s.grade() << endl

What do assns, mt, final mean inside of Student::grade?

  • Key are the fields of the current object - the object upon which grade was called

Student billy {...}
billy.grade(); // method call

Difference between method and function

  • Methods take a hidden extra parameter: this

    • a pointer to the object on which the method was called

billy.grade(); // this == &billy
  • Can write:

struct Student {
  ...
  float grade() { // method bodies can be written inside the class, lectures will do it for brevity, you should put them in .cc files
  return this->assns*0.4 + this->mt*0.2 + this->final*0.4
  }
};

Initializing Objects

Student billy {60,70,80} // intializing struct in C, OK, but limited

Better way:

  • write a method that initializes: Constructor

struct Student {
  int assns, mt, final;
  float grade();
  Student (int assns, int mt, int final();)
};

Student::Student (int assns, int mt, int final) {
  this->assns=assns;
  this->mt=mt;
  this->final=final;
}

Student billy {60,70,80}; //better way done!

Last updated