// Bank account objects in C #include #include /* Now want: checking account that charge fee for withdraws, and savings account that give bonus for deposits. But checking account doesn't change deposit and savings account doesn't change withdraw, and both accounts still wish to share inquiry Want an array of different types of accounts, and withdraw money from all of them. */ // names of tags: #define CHECKING 0 #define SAVINGS 1 typedef struct accstruct { int balance; } accstruct; typedef struct accstruct * account; // constructor account newaccount(int bal) { account A = (account)malloc(sizeof(struct accstruct)); A->balance = bal; // set init balance return A; } int inquiry(account A) { return A->balance; } void deposit(account A, int amt) { A->balance += amt; } void withdraw(account A, int amt) { if (amt<=A->balance) A->balance -= amt; } int moremoney(account A, account B) { return (A->balance > B->balance); } // extending code completely modularly - can't touch existing code, but want to borrow from it typedef struct extendstruct { // struct accstruct super; // important that this is not accstruct* (or account) // also important that this is the first element in the struct int balance; //important that this is the first element in the struct unsigned char tag; // 8 bit tag union { int fee; int bonus; } extra; } extendstruct; typedef extendstruct* extaccount; void bless(extaccount a, unsigned char t) { a->tag = t; } // constructors create extended accounts - checking or savings extaccount newchecking(int bal,int f) { extaccount A = (extaccount)malloc(sizeof(extendstruct)); A->balance = bal; A->extra.fee = f; bless(A,CHECKING); return A; } extaccount newsavings(int bal,int f) { extaccount A = (extaccount)malloc(sizeof(extendstruct)); A->balance = bal; A->extra.bonus = f; bless(A,SAVINGS); return A; } // No overloading in C, but that's not a big deal. explain overloading // new algorithm for withdraw: void withdraw_c(extaccount A, int amt) { if (amt+A->extra.fee <= A->balance) A->balance -= amt+A->extra.fee; } // new alg for ... void deposit_s(extaccount A, int amt) { A->balance += amt; if (amt>100000) A->balance += A->extra.fee; } // how to inherit? void ewithdraw(extaccount A, int amt) { if (A->tag==CHECKING) withdraw_c(A,amt); else withdraw((account)A,amt); // type cast needed! } void edeposit(extaccount A, int amt) { if (A->tag==SAVINGS) deposit_s(A,amt); else deposit((account)A,amt); } int einquiry(extaccount A) { return inquiry((account)A); } //// difference between dynamic dispatch and overloading. ///////// int main(int argc, char** argv) { extaccount myaccount = newchecking(300,1); extaccount youraccount = newsavings(100,1); ewithdraw(myaccount,100); // not myaccount->withdraw(50); edeposit(youraccount,100); if (moremoney((account)youraccount,(account)myaccount)) printf("you have more money than I do\n"); extaccount B[3]; B[0] = myaccount; B[1] = youraccount; if (argc>1) B[2] = newchecking(500,1); else B[2] = newsavings(500,1); // what's static type, dynamic type? // "polymorphic operation to withdraw $5 from each account: int i = 0; for(;i<3;i++) ewithdraw(B[i],5); // which function is being called? // even if ewithdraw was also called withdraw, you still can't tell can't // you? return 0; } /* If C had operator overloading, then instead of "ewithdraw", we could also have called it withdraw, but that would not be enough, since we would still need the DYNAMIC TYPE INFORMATION to determine which is the right version of withdraw to call at RUNTIME. */