///////// Uebung11_komplett.cpp //////////////////
//        = Uebung 10!

/* Quoter.cpp -- Random quote selection */
#include <iostream>
#include <cstdlib>      // Random number generator
#include <ctime>        // To seed random generator

using namespace std;


class Quoter {
  int lastquote;
public:
  Quoter();
  int lastQuote() const;
  const char *quote();
};


Quoter::Quoter() {
  lastquote = -1;
  srand(time(0));       // Seed random number generator
}


int Quoter::lastQuote() const {
  return lastquote;
}


const char *Quoter::quote() {
  static const char *quotes[] = {
    "Are we having fun yet?",
    "Doctors always know best",
    "Is it ... Atomic?",
    "Fear is obscene",
    "There is no scientific evidence "
    "to support the idea "
    "that life is serious",
    "Things that make us happy, make us wise",
  };

  const int qsize = sizeof quotes / sizeof *quotes;
  int qnum = rand() % qsize;
  while (lastquote >= 0 && qnum == lastquote) {
    qnum = rand() % qsize;
  }


  cout << "   qsize = " << qsize << endl;
  cout << "   sizeof quotes = " << sizeof quotes << endl;
  cout << "   sizeof *quotes = " << sizeof *quotes << endl;


  return quotes[lastquote = qnum];
}




int main() {
  Quoter q;

  q.lastQuote();
  for (int i = 0; i < 4; i++) {
    cout << q.quote() << endl;
  }
  system("pause");
  return 0;
}


/* constMemberArray.cpp */
#include <iostream>
using namespace std;

class Test {
  const int i;
  const int j;
  const int k;
public:
  Test(int, int, int);
  void printElems() const;
};

Test::Test(int i, int j, int k) : i(i), j(j), k(k) { }

void Test::printElems() const {
  cout << "Test object array: i : " << i
       << ", j : " << j
       << ", k : " << k << endl;
}


int main() {
  Test t1(0, 1, 2), t2(-3, 5, -73);
  t1.printElems();
  t2.printElems();
  system("pause");
  return 0;
}


/* constNoConstMembers.cpp */
#include <iostream>

using namespace std;


class Test {
  int i;
public:
  Test(int i) : i(i) { }

  void doSomething() const;
  void doSomething();
};



void Test::doSomething() const {
  cout << "Test::doSomething() const  called" << endl;
}


void Test::doSomething() {
  cout << "Test::doSomething()  called" << endl;
}



int main() {
  Test t1(15);
  const Test t2(99);

  t1.doSomething();
  t2.doSomething();
  
  system("pause");
  return 0;
}


/* constPointer.cpp --  Constant pointer arg/return */
#include <iostream>

using namespace std;

const int * const w() {
  static int i;
  return &i;
}

int main() {
  const int *const ccip = w();     // OK
  const int *cip2 = w();           // OK:
                                   //  You would also expect that the compiler refuses
                                   //  to assign the return value of w( ) to a non-const
                                   //  pointer, and accepts a const int * const, but it
                                   //  might be a bit surprising to see that it also
                                   //  accepts a const int *, which is not an exact match
                                   //  to the return type. Once again, because the value
                                   //  (which is the address contained in the pointer) is
                                   //  being copied, the promise that the original variable
                                   //  is untouched is automatically kept. Thus, the second
                                   //  const in const int *const is only meaningful when
                                   //  you try to use it as an lvalue, in which case the
                                   //  compiler prevents you. (B. Eckel)
  system("pause");
  return 0;
}


/* constReturnValues.cpp  --  compiler used: gnu g++ */
#include <iostream>

class X {
  int i;
public:
  X(int ii = 0);
  void modify();
};


X::X(int ii) { i = ii; }


void X::modify() { i++; }



X f5() {
  return X();
}


const X f6() {
  return X();
}


void f7(X& x) {         // Pass by non-const reference
  x.modify();
}


int main() {
  f5() = X(1);          // OK -- non-const return value
  f5().modify();        // OK
// f7(f5());            // Causes error:
                        //  constReturnValues.cpp:36: from rvalue of type `X'
                        //  constReturnValues.cpp:28: in passing argument 1 of `f7(X &)'

  // Causes compile-time errors:
// f6() = X(1);         // Causes error:
                        //  constReturnValues.cpp:41: passing `const X' as `this' argument
                        //  of `class X & X::operator =(const X &)' discards qualifiers
// f6().modify();       // Causes error:
                        //  constReturnValues.cpp: In function `int main()':
                        //  constReturnValues.cpp:44: passing `const X' as `this' argument
                        //  of `void X::modify()' discards qualifiers

// f7(f6());            // Causes error:
                        //  constReturnValues.cpp: In function `int main()':
                        //  constReturnValues.cpp:49: initialization of non-const reference
                        //  type `class X &'
                        //  constReturnValues.cpp:49: from rvalue of type `X'
                        //  constReturnValues.cpp:28: in passing argument 1 of `f7(X &)'
  system("pause");
}


/* constTypeQualifier.cpp */
#include <iostream>

using namespace std;


void tryToModifyArray(const int b[]) {
  b[0] /= 2;
  b[1] /= 2;
  b[2] /= 2;
}


int main() {
  int a[] = {10, 20, 30};
  tryToModifyArray(a);
  cout << a[0] << ' ' << a[1] << ' ' << a[2] << endl;
  system("pause");
  return 0;
}


// Error messages:
//  constTypeQualifier.cpp: In function `void tryToModifyArray(const int *)':
//  constTypeQualifier.cpp:8: assignment of read-only location
//  constTypeQualifier.cpp:9: assignment of read-only location
//  constTypeQualifier.cpp:10: assignment of read-only location


/* returnConst.cpp */
#include <iostream>

using namespace std;



class Point {
  double x;
  double y;
public:
  Point(double x = 0, double y = 0) : x(x), y(y) { }

  void setX(double x = 0) {
    this->x = x;
  }
};



const Point f(Point p) {
  return p;
}




int main() {
  Point p, p2(22, 33);

  p = f(p2);             // Funktioniert! Weshalb wohl?

// f(p2).setX(8)         // Fehler:
                         //  passing `const Point' as `this' argument of
                         //  `void Point::setX(double = 0)' discards
                         //  qualifiers

// f(p2) = p;            // Fuehrt zu Fehlermeldung:
                         //  passing `const Point' as `this' argument of
                         //  `class Point & Point::operator =(const Point &)'
                         //  discards qualifiers

  system("pause");
  return 0;
}


/* returnCopyTest.cpp */
#include <iostream>

using namespace std;


class CopyTest {
  int i;
public:
  CopyTest(int);
  CopyTest& set(int i);
  void print(int i) const;
};



CopyTest::CopyTest(int i) : i(i) {
  cout << "One arg constructor: " << i << endl;
}


CopyTest& CopyTest::set(int ii) {
  i = ii;
  return *this;
}


void CopyTest::print(int i) const {
  cout << i << ": CopyTest object with data member i = " << this->i << endl;
}




CopyTest ct(11);


CopyTest f() {
  ::ct.print(1);
  return ct;
}




int main() {
  f().set(99).print(2);

  ct.print(3);
  system("pause");
  return 0;
}
