【More Effective C++】条款35:将非尾端类设计为抽象类

考虑以下继承场景:

  • 通过指针的赋值会出现部分赋值的情况:只修改了Animal的数据成员,Lizard数据没有被修改
class Animal {
public:
    Animal(int data):data(data) {}

    Animal& operator=(const Animal& rhs) {
        if (&rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }

    int getData() const { return data; }
public:
    int data;
};

class Lizard : public Animal {
public: 
    Lizard(int data): Animal(data), l_data(data) {}
    // Lizard& operator=(const Lizard& rhs) {
    //     if (&rhs == this) return *this;
    //     this->data = rhs.data;
    //     return *this;
    // }
public:
    int l_data;
};

class Chicken : public Animal {
public: 
    Chicken(int data): Animal(data), c_data(data) {}
    // Chicken& operator=(const Chicken& rhs) {
    //     if (&rhs == this) return *this;
    //     this->data = rhs.data;
    //     return *this;
    // }
public:
    int c_data;
};

int main() {

    Animal a1(1);
    Animal a2(2);
    std::cout << a1.getData() << std::endl;
    a1 = a2;
    std::cout << a1.getData() << std::endl;

    return 0;
}

可以将拷贝赋值函数改为虚函数:

  • 但是又引入了异性赋值的情况,让人难以理解
class Animal {
public:
    Animal(int data):data(data) {}

    virtual Animal& operator=(const Animal& rhs) {
        if (&rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }

    int getData() const { return data; }
public:
    int data;
};

class Lizard : public Animal {
public: 
    Lizard(int data): Animal(data), l_data(data) {}
    virtual Lizard& operator=(const Animal& rhs) {
        if (&liz_rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }
public:
    int l_data;
};

class Chicken : public Animal {
public: 
    Chicken(int data): Animal(data), c_data(data) {}
    virtual Chicken& operator=(const Animal& rhs) {
        if (&rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }
public:
    int c_data;
};

int main() {

    Lizard liz(1);
    Chicken chick(2);
    Animal *pAnimal11 = &liz;
    Animal *pAnimal22 = &chick;
    *pAnimal11 = *pAnimal22;

    return 0;
}

解决办法是在拷贝赋值函数中进行类型转换:

  • 无法转型的情况抛出异常
class Animal {
public:
    Animal(int data):data(data) {}

    virtual Animal& operator=(const Animal& rhs) {
        if (&rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }

    int getData() const { return data; }
public:
    int data;
};

class Lizard : public Animal {
public: 
    Lizard(int data): Animal(data), l_data(data) {}
    virtual Lizard& operator=(const Animal& rhs) {
        const Lizard& liz_rhs = dynamic_cast<const Lizard&>(rhs);
        if (&liz_rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }
public:
    int l_data;
};

class Chicken : public Animal {
public: 
    Chicken(int data): Animal(data), c_data(data) {}
    virtual Chicken& operator=(const Animal& rhs) {
        const Chicken& liz_rhs = dynamic_cast<const Chicken&>(rhs);
        if (&rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }
public:
    int c_data;
};

为了解决简单对象的赋值情况需要赋值转型成本,可以将拷贝函数进行重载

class Animal {
public:
    Animal(int data):data(data) {}

    virtual Animal& operator=(const Animal& rhs) {
        if (&rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }

    int getData() const { return data; }
public:
    int data;
};

class Lizard : public Animal {
public: 
    Lizard(int data): Animal(data), l_data(data) {}
    Lizard& operator=(const Animal& rhs) {
        if (&liz_rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }
    virtual Lizard& operator=(const Animal& rhs) {
        return operator=(dynamic_cast<const Lizard&>(rhs));
    }
public:
    int l_data;
};

class Chicken : public Animal {
public: 
    Chicken(int data): Animal(data), c_data(data) {}
    Chicken& operator=(const Animal& rhs) {
        if (&rhs == this) return *this;
        this->data = rhs.data;
        return *this;
    }
    virtual Chicken& operator=(const Animal& rhs) {
        return operator=(dynamic_cast<const Chicken&>(rhs));
    }
public:
    int c_data;
};

未完待续。。。

相关推荐

  1. 07:多态基声明virtual析构函数

    2024-03-12 08:24:03       43 阅读
  2. 普通抽象

    2024-03-12 08:24:03       31 阅读
  3. 接口,抽象

    2024-03-12 08:24:03       31 阅读
  4. 接口和抽象

    2024-03-12 08:24:03       67 阅读
  5. c# 抽象

    2024-03-12 08:24:03       55 阅读
  6. 抽象abstract

    2024-03-12 08:24:03       44 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-12 08:24:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-12 08:24:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-12 08:24:03       87 阅读
  4. Python语言-面向对象

    2024-03-12 08:24:03       96 阅读

热门阅读

  1. Docker创建openresty容器

    2024-03-12 08:24:03       42 阅读
  2. 阿里云服务 安装 Node.js

    2024-03-12 08:24:03       36 阅读
  3. 代码随想录三刷day26

    2024-03-12 08:24:03       48 阅读
  4. [IAGC] Kafka消费者组的负载均衡策略

    2024-03-12 08:24:03       47 阅读
  5. 敏捷开发精准估算

    2024-03-12 08:24:03       45 阅读