struct
and class
.
They are more or less the same (except that in structs members
are public by default, and in classes they are private by
default. Of course that distinction won't make any sense at
this point, but in case you come back and read this later ...),
but historically come from different places. C++
gets struct
from C, the language that C++
extends. The term class
comes from
"object-oriented programming", which is a style of programming
C++ supports, but which we do not cover in this course. We
are going to use the keyword struct
to get you
familiar with what you'll see in the context of C programming
in your Systems Programming course. Of course this means that
in your Objected Oriented Programming course (taught using
Java) the keyword class
will be less familiar.
midpoint
that
takes two points and returns their midpoint.point
that encapsulated both the x and y
coordinates --- it's prototype would be
point midpoint(point a, point b);
. It
would be natural to sort 20 Midshipmen ordered by alpha codes
(which would order by class year) if there were a type
mid
that encapsulated both alpha code and name
--- I'd have an array mid *A = new mid[20]
.
Finally, it'd be natural to store student names along with
homework info if there was a type student
---
I'd just store it in an array of student
objects. Clearly, all of these problems scream out for the
ability of the user to wrap up one or more existing types
into one package and call it a new type. In C++,
struct is the mechanism that allows you to do this.
point
point
would make
such a function simple and natural. We need to wrap up a
double
for the x-coordinate and a
double
for the y-coordinate into a single
object of a new type - point
. Here's how that's
accomlished in C++:
struct point <--- Declares a new type called "point" { double x, y; <--- Says that a "point" contains two doubles named x and y }; <--- Don't forget the ;This struct definition, like function definitions, appears outside of
main
or of any other function definitions,
and it must appear before you try to use an object of type
point
. From the point of this definition onwards you
can use point
as a new type. If you want to access
the double x
within a point
object named
P
, you write P.x
--- note that P.x
is an object of type double, so anything you can do with a double
you can do with P.x
!
Moreover it is an l-value, it can be assigned to, passed
by reference, etc. The objects packeged together
in a new struct
are called data members.
We'll start off simple by creating an object of type
point
, reading values into the object, and printing
it out:
int main() { // Creates an object P of type point point P; // Reads & stores coordinate values cout << "Enter x-coord: "; cin >> P.x; cout << "Enter y-coord: "; cin >> P.y; // Writes out point P cout << "Point is (" << P.x << ',' << P.y << ")" << endl; return 0; }One very important thing to note here is that we can't say
cin >> P
in order to read into point
P
. Nor can we say cout << P
in order to write out point
P
.
Why? Because cin
and cout
know
nothing about the type point
!
On the other hand, cin >> P.x
works perfectly well,
because cin
is just reading into a
double
, which we know it does just fine.
Now, let's look at defining the function midpoint
:
point midpoint(point a, point b) { point m; m.x = (a.x + b.x)/2; m.y = (a.y + b.y)/2; return m; }Hopefully this code is pretty much self-explanatory. Notice that by wrapping up two
double
s in the type
point
I can, in a sense, return two objects from a
function! Take a look at this complete
program that reads two points from the user and prints out
their midpoint.
midpoint(P,Q)
.
struct
, cin
doesn't know how to read that
type, and cout
doesn't know how to write that type.
In fact, the compiler doesn't know how to do any of the implicit
or explicit conversions with your new types, so that neither
double(P)
, where P
is an object of type
point
, nor point(j)
, where
j
is an object of type int
will be
recognized. The only things the compiler knows how to do with your
user defined type are assignment using the =
operator, and copy for pass-by-value arguments in function calls.
These are done by assigning/copying each data member
independently. Most importantly, however, objects of user defined
type are created and detsroyed and passed around just like any
other type: scoping rules are the same, creation with
new
is the same, parameter passing is the same,
parameter type matching for function overloading is the same
... all of these things you've already learned still apply.
In fact, the string
, ifstream
, and
ofstream
objects that we've already been using are
struct
s rather than built-in types.
midpoint
function with arrays of two
double
s --- believe me, it'd be painful! Where
things really get interesting is when we wrap up objects of
different types in one object, because there we really can't use
arrays like we could for points. Let's think about our example of
Midhipmen names and alpha codes. We might define a
mid
as follows:
struct mid { int alpha; string first, last; };Notice that this struct has three data members, one of type
int
and two of type string
. Let's
consider using this type in the following problem: The file
Mids.txt
contains the names and
alpha codes of the Midshipmen in my two sections. I want to write
a program that will read that data and store it in an array for
later processing.
To test what I've done, we'll simply allow the
user to enter an alpha, and we'll return the name of the Mid with
that alpha, or an error message if none is found.
Creating the array and reading in data from the file is easy:
// Create and array of 41 Mids mid *A = new mid[41]; // Open file ifstream fin("Mids.txt"); // Read in mids for(int i = 0; i < 41; i++) fin >> A[i].alpha >> A[i].last >> A[i].first;Similarly, if
int
variable a
holds the value of the alpha code to search for, the code that
does the searching and prints the response is straightforward:
// search for alpha a int k = 0; while(k < 41 && A[k].alpha != a) k++; // print result of search if (k == 41) cout << "No Mid with that alpha was found!" << endl; else cout << A[k].first << " " << A[k].last << endl;
Enter triangle vertices: (0,0) (0,1) (1,0) Midpoint triangle verts: (0,0.5)(0.5,0.5)(0.5,0)Notice how my solution defines functions for writing and reading points!
writepoint
function a different name though.
n
vertices
defining an n
-gon, and produces a text file that
we can use with gnuplot to plot the n
-gon and
its "midpoint n
-gon".