2.构造函数
函数中有一个特殊的函数,那就是构造函数。因为一个类中大部分数据是隐藏的,总不能老是通过调用公共函数的方法来进行初始化。C++提供的就是构造函数的方法。
构造函数的建立规则是这样的。构造函数没有返回值,构造函数的名字和类的名字完全一模一样(大小写也相同),所有看到一个类声明中没有返回值,那么说明这个函数是构造函数,构造函数必须放在 public 下面。构造函数可以有很多种选择,这时候就需要用到函数重载的方法来定义了。
要是指针或者 C 风格的字符串.那么依然还是能够赋值,但是赋的是指针的值.所以,这里很容易有隐患,需要更加深层次的复制的时候就要关心这里.
如果成员本身就是类对象,则将使用这个类的复制构造函数来复制成员对象。因为类中包含了使用 new 初始化的指针成员,那么定义一个复制构造函数是很必须的,用来复制指向的数据,而不是一个指针.(浅复制只会复制指针的值,而不会深挖指针指向的结构,所以必须自己定义一个深复制.)
#ifndef MYSTRING_H_
#define MYSTRING_H_
#include<iostream>usingnamespacestd;classMyString{private:char*str;intlen;staticintnum_of_strings;//cin limits,只有const整形才能够在这里直接赋值!!!
staticconstintCINLIM=80;public://constructors and other methods
MyString();MyString(constchar*s);~MyString();//destructor
MyString(constMyString&ms);//copy constructor
intlenth()const{returnlen;}//overload operator methods
MyString&operator=(constMyString&ms);MyString&operator=(constchar*s);char&operator[](inti);//can access and modified
constchar&operator[](inti)const;//can access but can't modified
//overload operator friends
//输入输出
friendostream&operator<<(ostream&os,constMyString&ms);friendistream&operator>>(istream&is,MyString&ms);//字符串比较
friendbooloperator<(MyString&ms1,MyString&ms2);friendbooloperator>(MyString&ms1,MyString&ms2);friendbooloperator==(MyString&ms1,MyString&ms2);//静态方法
staticinthowMany();};#endif123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
mystring.cpp
#include"mystring.h"#include<iostream>#include<cctype>#include<cstring>usingnamespacestd;//首先初始化静态的变量
intMyString::num_of_strings=0;intMyString::howMany(){returnnum_of_strings;}//realize the constructor
MyString::MyString(){len=0;str=newchar[len+1];str[0]='\0';++num_of_strings;cout<<"using default constructor to init!: "<<str<<endl;cout<<"we have "<<num_of_strings<<" objects now!"<<endl<<endl;}MyString::MyString(constchar*s){len=strlen(s);str=newchar[len+1];strcpy(str,s);++num_of_strings;cout<<"using artificial constructor to init!: "<<str<<endl;cout<<"we have "<<num_of_strings<<" objects now!"<<endl<<endl;}MyString::~MyString(){--num_of_strings;cout<<"\""<<str<<"\""<<" deleted\n"<<endl;cout<<"we have "<<num_of_strings<<" objects now!"<<endl<<endl;delete[]str;}//realize the copy constructor
//本质就是进行深度复制,目的是保持每个对象的独立性
//不会是因为删除其中一个或是怎么的而影响到另外一个
MyString::MyString(constMyString&ms){++num_of_strings;len=ms.len;//重新分配空间
str=newchar[len+1];strcpy(str,ms.str);cout<<"using the copy constructor to init!: "<<str<<endl;cout<<"we have "<<num_of_strings<<" objects now!"<<endl<<endl;}ostream&operator<<(ostream&os,constMyString&ms){os<<"Infomation:\n";os<<"content of the string: "<<ms.str<<endl;os<<"lenth of the string: "<<ms.len<<endl<<endl;returnos;}istream&operator>>(istream&is,MyString&ms){charbuffer[MyString::CINLIM];is.get(buffer,MyString::CINLIM);if(is)ms=buffer;while(is&&is.get()!='\n')continue;returnis;}//重载赋值运算符需要注意的!
//函数应该避免将对象赋给自己,所以前面应当进行比较。
//函数会有一个清除当前内存的动作,因为以前可能会有数据在其中
//这就是为什么要比较两个对象的原因,因为相同的对象,删除其中任何的元素都会破坏另外的元素
//按照自己的需要进行深度复制
MyString&MyString::operator=(constMyString&ms){if(this==&ms){return*this;}delete[]str;len=ms.len;str=newchar[len+1];strcpy(str,ms.str);return*this;}MyString&MyString::operator=(constchar*s){delete[]str;len=strlen(s);str=newchar[len+1];strcpy(str,s);return*this;}char&MyString::operator[](inti){returnstr[i];}constchar&MyString::operator[](inti)const{returnstr[i];}booloperator<(MyString&ms1,MyString&ms2){return(strcmp(ms1.str,ms2.str)<0);}booloperator>(MyString&ms1,MyString&ms2){return(strcmp(ms1.str,ms2.str)>0);}booloperator==(MyString&ms1,MyString&ms2){return(strcmp(ms1.str,ms2.str)==0);}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
run.cpp
#include<iostream>#include<cstring>#include"mystring.h"usingnamespacestd;intmain(){MyStringms1;MyStringms2("leonardo dicapeio");MyStringms3=ms2;cout<<ms2;MyStringms4;ms4=ms2;cout<<ms4;cout<<"the numbers of objects we have:\n"<<MyString::howMany()<<endl;MyStringms5="fuck off";cout<<ms5;cout<<ms5[5]<<endl;if(ms1>ms5)cout<<"YES!!!"<<endl;elsecout<<"NO!!!!"<<endl;return0;}1234567891011121314151617181920212223
结果:
二:在构造函数中使用 new 的注意事项
1.首先,一旦有 new 的使用,意味着新内存空间的开辟和指针的使用,构造函数中用了 new,则析构函数中应该使用 delete
2.new 和 delete 应该相互兼容。new 对应于 delete,new []对应于 delete[]. 4.要是有多个构造函数,那么其中使用 new 的时候应该是用相同的类型.因为只有一个析构函数,只能在构造函数中使用同样的 new 的方式。 5.很据实际情况使用定义一个复制构造函数。这样可以进行深度复制,使得每个对象尽可能的保存独立。 6.根据实际情况重载赋值运算符=,进行深度复制,使得每个对象尽可能的保持独立。
四:有关返回对象的说明
1.返回指向 const 对象的引用
返回 const 引用的常见原因是为了提高效率,但是对于什么时候采用这一方法有一定的限制
如果函数返回(通过调用对象的方法或将对象作为参数传递给它的对象),可以通过返回引用来提高效率.
就用我们前面设计过的 Vector 类为例子
现在编写 Max 函数,返回两个 Vector 对象中模比较大的那个.
#include"bank.h"#include<iostream>usingnamespacestd;//先实现基类
Brass::Brass(conststring&name,conststring&accnum,doublebalance){m_name=name;m_accountNumber=accnum;m_balance=balance;}voidBrass::deposit(doublemoney){if(money<0){cout<<"the number should be positive!!!"<<endl;cout<<"the deposit has been canceled!!"<<endl<<endl;}else{m_balance+=money;cout<<"deposit succssful!!!"<<endl<<endl;}}voidBrass::withdraw(doublemoney){if(money<0){cout<<"the number should be positive!!!"<<endl;cout<<"the withdraw has been canceled!!"<<endl<<endl;}elseif(money<=m_balance){m_balance-=money;cout<<"deposit succssful!!!"<<endl<<endl;}else{cout<<"money you want to withdraw is exceed the balance!!"<<endl;cout<<"the withdraw has been canceled!!"<<endl<<endl;}}doubleBrass::getBalance()const{returnm_balance;}voidBrass::viewAcct()const{cout<<"Infomation:"<<endl;cout<<"Client: "<<m_name<<endl;cout<<"Account Number: "<<m_accountNumber<<endl;cout<<"Balance: "<<m_balance<<endl;}//实现派生类
BrassPlus::BrassPlus(conststring&name,conststring&accnum,doublebalance,doubleml,doubler):Brass(name,accnum,balance){maxLoan=ml;owesBank=0.0;rate=r;}BrassPlus::BrassPlus(Brass&br,doubleml,doubler):Brass(br){maxLoan=ml;owesBank=0.0;rate=r;}//重写函数
voidBrassPlus::withdraw(doublemoney){doubleba=getBalance();//虽然自己已经继承了m_balance,但是他是私有的,因此用基类公共的方法访问
if(money<=ba)Brass::withdraw(money);elseif(money<=ba+maxLoan-owesBank){doubleadvance=money-ba;owesBank+=advance*(1.0+rate);cout<<"advance: "<<advance<<endl;deposit(advance);Brass::withdraw(money);}else{cout<<"Too big and canceld"<<endl;}}voidBrassPlus::viewAcct()const{Brass::viewAcct();cout<<"new Info:"<<endl;cout<<"maxLoan:"<<maxLoan<<endl<<endl<<endl;}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
#include"bank.h"#include<string>#include<iostream>usingnamespacestd;constintMAX=4;intmain(){Brass*p[MAX];stringtemp;stringtempacc;doubletempba;charkind;for(inti=0;i<MAX;i++){cout<<"Enter client's name: ";getline(cin,temp);cout<<"Enter client's account number: ";cin>>tempacc;cout<<"Enter opening balance: ";cin>>tempba;cout<<"Enter 1 for Brass Account or 2 for BrassPlus Account: ";//出错诊断
while(cin>>kind&&(kind!='1'&&kind!='2'))cout<<"Enter 1 for Brass Account or 2 for BrassPlus Account: ";if(kind=='1'){p[i]=newBrass(temp,tempacc,tempba);}else{doubletmax,trate;cout<<"enter the loan limit: ";cin>>tmax;cout<<"enter the rate: ";cin>>trate;p[i]=newBrassPlus(temp,tempacc,tempba,tmax,trate);}while(cin.get()!='\n')continue;}cout<<endl;for(inti=0;i<MAX;i++){p[i]->viewAcct();cout<<endl;}for(inti=0;i<MAX;i++){deletep[i];}cout<<"Done!!!!\n"<<endl;return0;}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
文件解释:
1.其他的都是一模一样的,只是改变了 run.cpp 用作测试 2.第 8 行是用的基类声明的指针数组。 3.第 28 和 37 行是能够使得 new 出来的指针赋给基类指针的。即时 new 出来的也有派生类的指针。
4.New 出来的对象别忘记了 delete。 5.最后的结果就是,程序会根据指针指向的对象来做出相应的行为,而不是只会仅仅做出基类函数的行为。
#include"bank.h"#include<string>#include<iostream>usingnamespacestd;//实现抽象基类中可以实现的构造函数和其他函数
AcctABC::AcctABC(conststring&name,conststring&ID,doublebalance){m_name=name;m_ID=ID;m_balance=balance;}voidAcctABC::deposit(doublemoney){if(money<0)cout<<"money can't be a negetive number!!!"<<endl;else{m_balance+=money;cout<<"deposit DONE !!!!!!"<<endl;}}voidAcctABC::withdraw(doublemoney){m_balance-=money;}//实现Brass类以及其中的虚函数
Brass::Brass(conststring&name,conststring&ID,doublebalance):AcctABC(name,ID,balance){}voidBrass::withdraw(doublemoney){if(money<0)cout<<"money can't be a negetive number!!!"<<endl;elseif(money<=getBalance()){AcctABC::withdraw(money);cout<<"withsraw DONE!!!!!"<<endl;}elsecout<<"no enough money to withdraw"<<endl;}voidBrass::showIofo()const{cout<<"Infomation:"<<endl;cout<<"Name: "<<getName()<<endl;cout<<"ID"<<getID()<<endl;cout<<"Balance: "<<getBalance()<<endl;cout<<"----------end---------"<<endl<<endl;}//实现Brassplus类 以及其中的虚函数。
BrassPlus::BrassPlus(conststring&name,conststring&ID,doublebalance,doublemaxLoan,doublerate):AcctABC(name,ID,balance){m_maxLoan=maxLoan;m_rate=rate;m_owesBank=0.0;}BrassPlus::BrassPlus(constBrass&br,doublemaxLoan,doublerate):AcctABC(br){m_maxLoan=maxLoan;m_rate=rate;m_owesBank=0.0;}voidBrassPlus::withdraw(doublemoney){if(money<0)cout<<"money can't be a negetive number!!!"<<endl;elseif(money<=getBalance()){AcctABC::withdraw(money);cout<<"withsraw DONE!!!!!"<<endl;}else{cout<<"other method to shutdown!!!"<<endl;}}voidBrassPlus::showIofo()const{cout<<"Infomation:"<<endl;cout<<"Name: "<<getName()<<endl;cout<<"ID"<<getID()<<endl;cout<<"Balance: "<<getBalance()<<endl;cout<<"MaxLoan: "<<m_maxLoan<<endl;cout<<"Rate: "<<m_rate<<endl;cout<<"OwesBank: "<<m_owesBank<<endl;cout<<"----------end---------"<<endl<<endl;}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
main.cpp
include"bank2.h"include<string>include<iostream>usingnamespacestd;constintMAX=4;intmain(){//从抽象基类定义出来的指针
AcctABC*p[MAX];stringtemp_name;stringtemp_ID;doubletemp_balance;charkind;inti;for(i=0;i<MAX;i++){cout<<"Enter client's name: ";getline(cin,temp_name);cout<<"Enter client's ID: ";cin>>temp_ID;cout<<"Enter client's balance: ";cin>>temp_balance;cin>>kind;cout<<"Enter the kind you want to create."<<endl;cout<<"1 for Brass and 2 for BrassPlus:";while(cin>>kind&&(kind!='1'&&kind!='2'))cout<<"Enter 1 or 2!!!"<<endl;if(kind=='1')p[i]=newBrass(temp_name,temp_ID,temp_balance);else{doubletemp_max,temp_rate;cout<<"Enter the maxloan:";cin>>temp_max;cout<<"Enter the rate:";cin>>temp_rate;p[i]=newBrassPlus(temp_name,temp_ID,temp_balance,temp_max,temp_rate);}while(cin.get()!='\n')continue;}cout<<endl;for(i=0;i<MAX;i++){p[i]->showIofo();cout<<endl;}for(i=0;i<MAX;i++){deletep[i];}cout<<"----------DONE!----------"<<endl;return0;}