习题练手(1):回忆知识点

158 阅读1分钟

今天早上学妹说运算符重载好难,让我帮她看两道题目:

image.png 呜呜呜,我也觉得难啊。我再一看题目,杂连模板都整出来了。这现在大学进度这么快么?不过,为了好好表现一下,我还是硬着头皮上了。

第一题

1. 涉及知识点

这道题目主要涉及的要点有继承关系下构造函数,多态(基类指针指向派生类对象),运算符重载(+=<<)等等。

2. 代码

#include<iostream>
#include<string>
class Animal{
protected:
    std::string name;
public:
    Animal(std::string n):name(n){}
    
    virtual Animal& operator += (int growAge){return *this;}
    friend std::ostream& operator << (std::ostream &os, Animal *p){
        p->printInfos();
        return os;
    }
    virtual void printInfos() = 0;
};

class Horse:public Animal{
    int age;
public:
    Horse() = default;
    Horse(std::string n, int h):Animal(n),age(h){}
    virtual void printInfos()override{
        std::cout<<name<<": "<<age<<" years old"<<std::endl;
    }
};

class Pig:public Animal{
    int age;
public:
    Pig() = default;
    Pig(std::string n, int p):Animal(n),age(p){}
    virtual Pig& operator += (int growAge)override{
        std::cout<<"Pig: "<<name<<" grows old"<<std::endl;
        this->age += growAge;
        return *this;
    }
    virtual void printInfos()override{
        std::cout<<name<<": "<<age<<" years old"<<std::endl;
    }
};

3. 小结

我晓得多态情况下,基类指针指向派生类对象可以调用派生类的成员函数,所以我比较朴素的在两个派生类中重载了流输出运算符,以至于我运行语句cout<<animal[0]<<animal[1]时输出的总是00BC21F000BC1F70两个地址。由于忽略了友元函数不算类的成员函数这一点,所以基类Animal的指针还是使用基类默认的输出行为,故显示的是指针数组animal的元素值。
于是我在基类中用纯虚函数声明了一个输出接口,然后在派生类中各自实现,再再基类中重载流输出运算符,并通过基类指针调用该接口,由于多态,实际上调用的是实际对象的接口实现。

第二题

1. 涉及知识点

这道题目主要涉及的要点有运算符重载([]<<),模板等等。

2. 代码

#include<iostream>
template<class T>{
    T x,y,z;
    Point3D() = default;
    Point3D(T a, T b, T c):x(a),y(b),z(c){}
    friend std::ostream& operator << (std::ostream &os, const Point3D &p){
        os<<p.x<<" "<<p.y<<" "<<p.z<<std::endl;
        return os;
    }
};

template<class T, int len>
class Skeleton{
    Point3D<T>joints[len];
public:
    Skeleton(Point3D<T>*j){
        for(int i=0;i<len;++i){
            joints[i]=j[i];
        }
    }
    Point3D<T>& operator [] (const char *str){
        if(str=="HEAD"){
            return joints[0];
        }
        else if(str=="NECk"){
            return joints[len - 1];
        }
    }
};

3. 小结

这道题目粗一看有模板,其实就是“水货”,主要还是运算符重载。再有一点要注意的是,在自定义了构造函数后,编译器并不会再合成默认构造函数。而Skeleton的对象中包含复合类成员数组joints,需要调用Point3D类的默认构造函数,所以要注意添加。但这个问题在编译期间就可以被编译器指出从而被修正。