Recent Changes - Search:

Coding C++

Computing

Object: Functions, parameters and Data Structures

Trail Index | Objects | Functions

Going from a naive implementation of 2 functions to a clean, structured one in which duplication has been removed.

Step 1 - Basic

/*
 * Objects: two identical functions with separate parameters.
 * Easy to mix up variable names..
 */

#include <iostream>
#include <cmath>

double k1; // global, non const, not initialized
double k2; // global, non const, not initialized
double f1(const double x) {
        return sqrt(k1)*x+k2*x*x;
}

double ka; // global, non const, not initialized
double kb; // global, non const, not initialized
double f2(const double x) {
        return sqrt(ka)*x+k2*x*x; // whoops should have been kb, not k2 !
        // the compiler will not help you here
}

int main() {
        k1=2.;
        k2=3.;
        const double y1=f1(3.);
        std::cout<< "f1("<<3.<<")="<<y1<<"\n";

        ka=4.;
        kb=5.;
        const double y2=f2(3.);
        std::cout<< "f2("<<3.<<")="<<y2<<" - wrong!!\n";
}

Step 2 - Choose better variable names

/*
 * Objects: two identical function with parameters.
 * Parameter names specify what they are related to.
 * Cleaner, safer, but verbose
 */

#include <iostream>
#include <cmath>

/*
 * prepend function name to parameter name,
 * in this case using "_",
 * which has no syntactical meaning for C++:
 * it's like any other letter or number
 */

double f1_k1;
double f1_k2;
double f1(const double x) {
        return sqrt(f1_k1)*x+f1_k2*x*x;
}

double f2_ka; // could have called it f1_k1
double f2_kb;
double f2(const double x) {
        return sqrt(f2_ka)*x+f2_kb*x*x; // OK now
}

/**
 * nothing different here
 */

int main() {
        f1_k1=2.;
        f1_k2=3.;
        const double y1=f1(3.);
        std::cout<< "f1("<<3.<<")="<<y1<<"\n";
       
        f2_ka=4.;
        f2_kb=5.;      
        const double y2=f2(3.);
        std::cout<< "f2("<<3.<<")="<<y2<<"\n";
}

Step 3 - Use, and reuse, a data structure

A class or struct is like a mould to make objects. From one class, you can create many "instances".

But if you don't give too much importance to the titles, this is not anything new: like you have multiple variables of type double, you have multiple variables of type DataPoint.

/*
 * two functions with parameters in struct
 * Clearer, but still verbose, still possible to mix it up
 * Note: this would be reasonably good plain C (not C++) code
 */

#include <iostream>
#include <cmath>

/**
 * data structure,
 * groups together the related variables
 * (function parameters, in this case)
 *
 * This is just a "definition", not a "declaration"
 * it does not really create a variable,
 * it only defines a new type
 */

struct FunctionParameters {
        double k1;
        double k2;
};

/**
 * Declare an "instance" of the data structure,
 *
 *  This is called "instantiating an object"
 * Must declare it before the function!
 * So it still needs to be global
 */

FunctionParameters fp1;

/**
 * the function is not really different from before
 * Just note the use of "." to identify instance.variable
 */

double f1(const double x) {
        return sqrt(fp1.k1)*x+fp1.k2*x*x;
}

FunctionParameters fp2;
double f2(const double x) {
        return sqrt(fp2.k1)*x+fp2.k2*x*x;
}

/**
 * usage of f1 and f2 is very similar,
 * just note the fp1.k1 instead of f1_k1
 */

int main() {
        fp1.k1=2.;
        fp1.k2=3.;
        const double y1=f1(3.);
        std::cout<< "f1("<<3.<<")="<<y1<<"\n";
       
        fp2.k1=4.;
        fp2.k2=5.;
        const double y2=f2(3.);
        std::cout<< "f2("<<3.<<")="<<y2<<"\n";
}

Step 4 - struct as parameter

/**
 * two functions with parameters in struct
 * Clearer, but still verbose, still possible to mix it up
 * Note: this would be reasonably good plain C (not C++) code
 */

#include <iostream>
#include <cmath>

/**
 * data structure as in Function_3
 * Still only a definition, not declaration.
 */

struct FunctionParameters {
        double k1;
        double k2;
};

/**
 * now we pass all parameters to the function.
 * In this way we only write the function once,
 * and we do not need globals!
 */

double f(const FunctionParameters fp, const double x) {
        return sqrt(fp.k1)*x+fp.k2*x*x;
}

/**
 * The usage of f() is now quite different,
 * we must pass it the whole instance of struct as parameter
 * Note that we don't need the globals anymore,
 * we can create the instances of struct where we need them!
 */

int main() {
        {
                FunctionParameters fp1; // create instance, locally!
                fp1.k1=2.;
                fp1.k2=3.;
                const double y1=f(fp1,3.); // looks odd, doesn't it?
                std::cout<< "f1("<<3.<<")="<<y1<<"\n";
        }
        /*
         * now using separate scopes, it's
         * impossible to confuse fp1 and fp2
         */

        {
                FunctionParameters fp2;
                fp2.k1=4.;
                fp2.k2=5.;
                const double y2=f(fp2,3.);
                std::cout<< "f2("<<3.<<")="<<y2<<"\n";
        }
}

< Objects | Trail Index | Objects >

Edit - History - Print - Recent Changes - Search
Page last modified on April 10, 2007, at 11:41 pm