You should give the input statement blocks, the expected output blocks for each input block, and a description of how the tests show.
The key here is to remember that the operators in the assignment all have the same precedence, which is equivalent to having no precedence at all. Only associativity and parentheses determine the order of evaluation.
The first test case checks for identical precedence. The input statement block is
a = 1 + 2 * 3
With identical precedence for operators +
and *
, left to right
associativity determines the order of evaluation, which is equivalent to (1
+ 2) * 3
, producing the correct output statement block
a = 9
An optimizer that incorrectly assigned C++ precedence to the operators would
evaluate *
first, producing the incorrect output statement block
a = 7
A lot of people submitted test cases that contained only a single binary operator
a = 7 + 3
or contained more than one operator of the same kind
a = 7 + 3 + 9
or contained several operators of different kinds but with full parenthesization
a = (7 + ((9 / 3) * 8))
None of these test cases are particularly helpful when testing for correct precedence handling.
A
, B
, and C
are all related to one another. The
following code
int main() { try { throw new A(); } catch (A*) { cout << "caught an A*.\n"; } catch (C*) { cout << "caught a C*.\n"; } catch (B*) { cout << "caught a B*.\n"; } try { throw new B(); } catch (A*) { cout << "caught an A*.\n"; } catch (C*) { cout << "caught a C*.\n"; } catch (B*) { cout << "caught a B*.\n"; } try { throw new C(); } catch (A*) { cout << "caught an A*.\n"; } catch (C*) { cout << "caught a C*.\n"; } catch (B*) { cout << "caught a B*.\n"; } cout << "\n"; try { throw new A(); } catch (B*) { cout << "caught a B*.\n"; } catch (C*) { cout << "caught a C*.\n"; } catch (A*) { cout << "caught an A*.\n"; } try { throw new B(); } catch (B*) { cout << "caught a B*.\n"; } catch (C*) { cout << "caught a C*.\n"; } catch (A*) { cout << "caught an A*.\n"; } try { throw new C(); } catch (B*) { cout << "caught a B*.\n"; } catch (C*) { cout << "caught a C*.\n"; } catch (A*) { cout << "caught an A*.\n"; } }
produces the following output
caught an A*. caught a C*. caught a C*. caught a B*. caught a B*. caught a C*.
What is the parent-child relation between the classes A
, B
, and
C
? Explain.
The first try statement throws an A*
, which is caught by the A*
block; nothing to learn here.
The second try statement throws a B*
, which is caught by the C*
block. This tells us that B
is a child of C
. But, we also know that
A
can't be a parent of B
because otherwise the A*
block would
have caught the B*
.
The third try statement throws a C*
, which is caught by the C*
block;
nothing new here. But, again, because the A*
block didn't catch the
C*
, then A
can't be a parent of C
.
The fourth try statement throws a A*
, which is caught by the B*
block: A
must be a child of B
.
The fifth try statement throws a B*
, which is caught by the B*
block;
nothing to learn here.
The sixth try statement throws a C*
, which is caught by the C*
block;
nothing to learn here, but B
can't be C
's parent because otherwise
B*
would have been caught the C*
.
In summary: A
can't be anybody's parent, and B
can't be C
's
parent. Because they're all the classes are related, C
must be B
's
parent and B
must be C
's parent.
vector<double> homework;
double x;
// invariant: homework
contains all the homework grades
while (cin >> x)
homework.push_back(x);
Do you think the invariant is acceptable? If you think the invariant is acceptable, make sure you explain how it's initially true; if you think the invariant's unacceptable, propose an alternative.
The problem with this invariant is that it might not be initially true; in
fact, the only time it will be initially true is when cin
is empty.
To discover a better invariant, it's a good idea to look at the loop that's being described and try to capture what the loop is trying to do (this is backwards, of course - the invariant should be written before the loop is written). The trick is to describe the loop's behavior in a way that is always true.
The loop copies values from cin
to homework
; that is, homework
contains some initial part of the homework grades. This suggests the invariant
cin
, homework
) contains all the
homework grades.
This invariant is initially true, because cin
contains all the grades and
homework
is empty. Each iteration of the loop removes a value from
cin
and pushes it into homework
, preserving the truth of the
invariant. When the loop ends,
cin
, homework
) contains all the
homework grades, and cin
is empty.
is true, which means that homework
contains all the homework grades, which
is a pretty accurate description not only of the loop's behavior, but also of
the the behavior needed by the rest of the code.
The three formal parameter kinds are
This page last modified on 21 February 2002.