Most of the code we have seen for classes has been defined inside the braces that mark the class. C++ also allows us to put the code outside the class, even in a different file. In the multi-file projects notes you can see an example of this. One reason to do this is to avoid having the class be too cluttered. It can be easier to read and understand the class if you just see the declaration and not all the details in the code.
One problem with this idea is how does the compiler know that a function it sees in another file or just outside the class is actually a method on the class? We handle this two ways. The first is that we put the function prototype for the method inside the class. The second is that we use the name of the class as a prefix to the function name. We will use one of the half adder veriations As an example. First, here is the original code.
#includeusing namespace std; class half_adder { public: // constructor to initialize the data // half_adder 2 arg constructor half_adder(int a, int b) { one=a; two=b; } // half_adder 0 arg constructor // default data values are 0 half_adder() { one=0; two=0; } // need some methods to get the results int get_sum() {return sum;} int get_carry() {return carry;} // change the data values; int set_data(int a, int b) {one=a; two=b;} /** * half_add() - uses the two bits and sets the sum and carry values */ void add() { int x1 = !one & two; // not a and b int x2 = one & !two; // a and not b carry = one & two; // This is the carry sum = x1 | x2; // This is the sum } // add void print() { cout << one << " + " << two << " = " << sum << " with a carry of " << carry << endl; } // print private: int sum; // holds the sum of the two bits int carry; // holds the carry bit int one, two; // the two data bits }; // half_adder
We are going to put the code for the add() and print() methdods outside the class. We could put the others outside as well, but won't. As a rule of thumb, if it fits in one or two lines, leave it inside.
#includeusing namespace std; class half_adder { public: // constructor to initialize the data // half_adder 2 arg constructor half_adder(int a, int b) { one=a; two=b; } // half_adder 0 arg constructor // default data values are 0 half_adder() { one=0; two=0; } // need some methods to get the results int get_sum() {return sum;} int get_carry() {return carry;} // change the data values; int set_data(int a, int b) {one=a; two=b;} /* * half_add() - uses the two bits and sets the sum and carry values */ void add(); void print(); private: int sum; // holds the sum of the two bits int carry; // holds the carry bit int one, two; // the two data bits }; // half_adder /** * half_add() - uses the two bits and sets the sum and carry values */ void half_adder::add() { int x1 = !one & two; // not a and b int x2 = one & !two; // a and not b carry = one & two; // This is the carry sum = x1 | x2; // This is the sum } // add void half_adder::print() { cout << one << " + " << two << " = " << sum << " with a carry of " << carry << endl; } // print
Note that inside the class we left the function prototype. That is, the return type, name and arguments (if any) of the function. We copied the function outside the braces of the class. The only change we made there was to add the name of the class before the function name and after the return type like this:
half_adder::print()Think of it as if the true name of every function includes the class name. It's just that when the function isn't part of a class, we skip using it. This allows us to even put the method code in another file because the compiler has to see the whole class as it compiles the code. So even if it only sees the class declaration, it will see the actual code eventually or generate an error. This is much like how we use function prototypes if we want to put the function code after the main.