天天看点

不要对数组进行多态

这是effective上的一条,当初我的理解并没有错,这个操作会造成指针访问数组的偏移发生变化,导致无法正常访问,只有一种情况是不会出错,那就是父类和派生类的大小相等,这样偏移量也就相等。再说一下我的想法吧,我天真的认为一个virtual 函数可以解决这个问题的,事实证明我的想法是真的可笑,但这次的尝试让我在大佬的教导下对多态和类有了新的认知。

话不多说贴上代码:

#include<iostream>  
using namespace std;
class Animal {
public:
    char *name;
    Animal(){}
    Animal(char *tmp) {
        name = tmp;
        cout << "construct" << endl;
    }
    Animal(const Animal&a,char *tmp) {
        name = tmp;
        cout << "copy construct" << endl;
    }
    Animal&operator=(const Animal &a) {
        this->name = a.name;
        cout << "operator" << endl;
        return *this;
    }
    virtual ~Animal(){}
    virtual void print(Animal arr[],int num) {
        for (int i = ; i < num; i++)
            cout << arr[i].name<<" ";
    }
};
class waterAnimal :public Animal {
public:
    int temp=;
    waterAnimal() {}
    waterAnimal(char *tmp):Animal(tmp){}
    ~waterAnimal(){}
    void print(Animal arr[], int num) {
        cout << "waterAnimal" << endl;
        for (int i = ; i < num; i++)
            cout << arr[i].name << " ";
    }
};
void display(Animal *arr, int num) {
    arr->print(arr, num);
}
int main() {
    Animal *wtarr = new waterAnimal[]{ "fish","shrimp", "whale" };
    display(wtarr, );
    system("pause");
}
           

我刚开始construct也拼错了,写成了destruct,真的是尴尬…

这段代码中,main函数里的动态分配数组wtarr初始化,然后调用display,结果会显示我调用了派生类的print,但是数组的输出会乱,甚至出现数组越界报错,这是合情合理的,因为派生类的大小要比父类大,偏移量不同。现在再说一下我刚开始写的吧,只在main的wtarr的初始有不同:

Animal *wtarr = new waterAnimal[];
    wtarr[] = { "fish" };
    wtarr[] = { "shrimp" };
    wtarr[] = { "whale" };
    display(wtarr, );
           

这种赋值输出并不会出错,而且一切正常,原因是{“fish”}是先进行了带参构造形成临时对象,然后再调用了赋值构造函数,将临时对象赋值给wtarr[i],其中的带参构造是父类的,你没听错,是父类的,所噫wtarr中的对象是Animal类型的,所以调用子类的print时就不会出现偏移量不同而导致的数组越界。

这种想法很是单纯,也显示了我的知识欠缺,没有考虑周全…在此也贴上一个讲解的更加细致的博客:http://blog.csdn.net/qq51931373/article/details/52095318

继续阅读