从派生类到基类的转换
基本使用方法:
double print_total(const Item_base&, size_t){std::cout << "test" << std::endl; return 0.3;} //function with an Item_base reference parameter Item_base item; //object of base type //ok:use pointer or reference to Item_base to refer to an Item_base object print_total(item, 10); //passes reference to an Item_base object Item_base *p = &item; //p points to an Item_base object Bulk_item bulk, *q; //object of derived type //ok:can bind a pointer or reference to Item_base to a Bulk_item object print_total(bulk, 10); //passes reference to the Item_base part of bulk p = &bulk; //p points to the Item_base part of bulk q = &bulk; std::cout << p << " : " << q << std::endl;//地址是相同的
亮点不是传递参数,是指针,基类指针p也能指向派生类派生类对象拥有基类子对象,那么p指向的算派生类对象还是基类子对象?至少和q地址一样
地址相同也可能说明类中空间存储的顺序是先放基类子对象,再放派生类对象的那部分。
关于覆盖虚函数机制:
Item_base *baseP = &derived; double d = baseP->Item_base::net_price(42);//错误的原例 d = baseP->net_price(42); //对照组
上边这个书中烂例子(p481)表达出来的东西是错误的,不是说Item_base::将强制调用基类版本,而是使用Item_base指针本身就强制转换过了,这个过程已经“强制”的覆盖了(应该说指向的是派生类对象的基类子对象),编译器都将它当作基类对象(p480)。
只有下面例子的Bulk_item指针才能表达出这个覆盖作用。
Bulk_item *derivedP = &derived; d = derivedP->net_price(42); std::cout << d << std::endl; d = derivedP->Bulk_item::net_price(42); std::cout << d << std::endl; d = derivedP->Item_base::net_price(42); std::cout << d << std::endl;
//主调函数 void print_total(std::ostream &os, const Item_base& item, size_t n){ os << "ISBN: " << item.book() //calls Item_base::book << "\tnumber sold: " << n << "\ttotal price: " //virtual call:which version of net_price to call is resolved at run time << item.net_price(n) << std::endl;//被调用的虚函数net_price() } //测试virtual函数的多态性~测试代码: Item_base base; Bulk_item derived; //print_total makes a virtual call to net_price //手动调用基类做对照 std::cout << base.net_price(10) << std::endl; std::cout << derived.net_price(10) << std::endl; //传递引用 print_total(std::cout, base, 42); //calls Item_base::net_price print_total(std::cout, derived, 42); //calls Bulk_item::net_price
虚函数与默认实参概念:默认实参是编译时确定的,如果一个调用省略了具有默认值的实参(how?就是不输入参数的调用例如fcn()吧),则所用的值由调用该函数的类型(谁调用?是在类内调用函数还是传递类来调用函数)定义,与对象的动态类型无关(动态类型有什么玄机)
如果用指针或引用调用虚函数,基类指针调用基类虚函数声明中指定的值,派生类使用派生类的。
====================================================================================================================================语言障碍太大了,简单的道理被作者费力的翻译成复杂的语言,还要有个中文翻译,最后复杂的语言被读者费力解读,最后在脑中还是演变成简单几句话的理解~!需要一个更好的方法更快速的学习,还不遗漏书中重要的逻辑(其实还是粗略的看最快,重点应该以后回来查阅,书是自己的。but,有时候太粗略的看还不能理解,毕竟示例代码有限,要自己写不少实验代码,读太粗略自己写不出来就完蛋,恼火~!)
书中那几句废话不就是说,默认实参和这个函数的多态是配套的么(不是本来默认实参就该是函数的一部分么,真搞不懂为什么弄一大堆复杂的语言来描述废话,难道默认实参不是绑定于函数的(mark)),你调用基类版本的virtual函数,当然是使用基类的默认实参,调用派生类版本的就用派生类版本的默认实参,另外,指针和引用也遵循这个原则(前文也有了,指针的作用实际上是个小强制转换,这个“强制转换”是因,调用转换成的基类或者派生类类型的virtual函数从而使用该版本的默认实参是果。。)
/*virtualArgument.cpp*/ Item_base base; Bulk_item derived; //如果输入了实参,比如11,那就传递11,基类派生类一样 std::cout << base.net_price(11) << std::endl; std::cout << derived.net_price(11) << std::endl;//如果不输入实参,使用默认实参,根据基类和派生类的调用情况~各找各妈去std::cout << base.net_price() << std::endl;
std::cout << derived.net_price() << std::endl;
Item_base *baseP = &derived;//利用指针把派生类“转换”成基类std::cout << baseP->net_price() << std::endl;//Bulk_item *deriveP = &base;//不能把基类往派生类转 ====================================================================================================================================pe15_8.cpp
找错修正题,搞不定了(mark)
到底谁访问基类,谁虚,弄得太乱了
//解释程序,找问题 #include<iostream> struct base{//另一处提示: note: base::base(const base&) base(const std::string &s): basename(s) {}//和derived错误提示绑定的提示: note: candidates are: base::base(const std::string&) std::string name(){return basename;} virtual void print(std::ostream &os) {os << basename;} private://默认public std::string basename; }; struct derived: public base{//题中错误:没有类派生列表 derived(int i): mem(i){}//错误提示也很令人惊讶: error: no matching function for call to ‘base::base()’ void print(std::ostream &os) {//题中错误:函数体内的print()调用的参数列表不像是使用,而是声明(ostream &os) base::print(os);//题中错误:没用base::强制调用基类的print(),不过我加了也不对。。。。恼火~! os << " " << mem;//而且参数列表中的局部变量os,无法给外边的os << " " << mem;使用 } private: int mem; }; int main(){ base b1("jet"); derived d1(10); b1.print(std::cerr);//玩的,cerr也是显示 d1.print(std::cout); }
习题15.9因为15.8没解决,15.9也晾着