⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mc6.htm

📁 有基本了解的程序员或程序爱好者而做
💻 HTM
📖 第 1 页 / 共 5 页
字号:
Animal *pAnimal2 = &liz2;...*pAnimal1 = *pAnimal2;                          // calls operator= taking                                                 // a const Animal&In fact, given this latter operator=, it's simplicity itself to implement the former one in terms of it: Lizard& Lizard::operator=(const Animal& rhs){  return operator=(dynamic_cast<const Lizard&>(rhs));}This function attempts to cast rhs to be a Lizard. If the cast succeeds, the normal class assignment operator is called. Otherwise, a bad_cast exception is thrown.Frankly, all this business of checking types at runtime and using dynamic_casts makes me nervous. For one thing, some compilers still lack support for dynamic_cast, so code that uses it, though theoretically portable, is not necessarily portable in practice. More importantly, it requires that clients of Lizard and Chicken be prepared to catch bad_cast exceptions and do something sensible with them each time they perform an assignment. In my experience, there just aren't that many programmers who are willing to program that way. If they don't, it's not clear we've gained a whole lot over our original situation where we were trying to guard against partial assignments.Given this rather unsatisfactory state of affairs regarding virtual assignment operators, it makes sense to regroup and try to find a way to prevent clients from making problematic assignments in the first place. If such assignments are rejected during compilation, we don't have to worry about them doing the wrong thing.The easiest way to prevent such assignments is to make operator= private in Animal. That way, lizards can be assigned to lizards and chickens can be assigned to chickens, but partial and mixed-type assignments are forbidden: class Animal {private:  Animal& operator=(const Animal& rhs);               // this is now  ...                                                 // private};class Lizard: public Animal {public:  Lizard& operator=(const Lizard& rhs);  ...};class Chicken: public Animal {public:  Chicken& operator=(const Chicken& rhs);  ...};Lizard liz1, liz2;...liz1 = liz2;                                    // fineChicken chick1, chick2;...chick1 = chick2;                                // also fineAnimal *pAnimal1 = &liz1;Animal *pAnimal2 = &chick1;...*pAnimal1 = *pAnimal2;                          // error! attempt to call                                                // private Animal::operator=Unfortunately, Animal is a concrete class, and this approach also makes assignments between Animal objects illegal: Animal animal1, animal2;...animal1 = animal2;                              // error! attempt to call                                                // private Animal::operator=Moreover, it makes it impossible to implement the Lizard and Chicken assignment operators correctly, because assignment operators in derived classes are responsible for calling assignment operators in their base classes (see Item E16): Lizard& Lizard::operator=(const Lizard& rhs){  if (this == &rhs) return *this;  Animal::operator=(rhs);                       // error! attempt to call                                                // private function. But                                                // Lizard::operator= must                                                // call this function to  ...                                           // assign the Animal parts}                                               // of *this!We can solve this latter problem by declaring Animal::operator= protected, but the conundrum of allowing assignments between Animal objects while preventing partial assignments of Lizard and Chicken objects through Animal pointers remains. What's a poor programmer to do?The easiest thing is to eliminate the need to allow assignments between Animal objects, and the easiest way to do that is to make Animal an abstract class. As an abstract class, Animal can't be instantiated, so there will be no need to allow assignments between Animals. Of course, this leads to a new problem, because our original design for this system presupposed that Animal objects were necessary. There is an easy way around this difficulty. Instead of making Animal itself abstract, we create a new class AbstractAnimal, say consisting of the common features of Animal, Lizard, and Chicken objects, and we make that class abstract. Then we have each of our concrete classes inherit from AbstractAnimal. The revised hierarchy looks like this,and the class definitions are as follows: class AbstractAnimal {protected:  AbstractAnimal& operator=(const AbstractAnimal& rhs);public:  virtual ~AbstractAnimal() = 0;                     // see below  ...};class Animal: public AbstractAnimal {public:  Animal& operator=(const Animal& rhs);  ...};class Lizard: public AbstractAnimal {public:  Lizard& operator=(const Lizard& rhs);  ...};class Chicken: public AbstractAnimal {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -