如何在 C++ 中改进以下代码的 UML 模型化?

How can I improve my UML modellisation of the following code in C++?

我正在使用 UML 在 C++ 中对基本代码建模。 我有初稿。 我想就如何改进它或者我是否遗漏了什么或者图表是否有问题提供反馈。

UML 图:

代码:

#include <ctime>
#include <functional>
#include <iostream>
#include <math.h>
#include <numeric>
#include <string>
#include <vector>


// CLASS: declaration -------------------------------------
// # Animal ...............................................
class Animal{
    private:
        std::string name;
        double height;
        double weight;

        // member of a class as static { bit.ly/2EXnDTW }
        static int numOfAnimals;
    public:
        static int GetNumOfAnimals(){return numOfAnimals;}

        void SetName(std::string name){this->name = name;} //<mutator/SETTER
        std::string GetName(){return name;} //<accessor/GETTER

        void SetHeight(double height){this->height = height;}
        double GetHeight(){return height;}

        void SetWeight(double weight){this->weight = weight;}
        double GetWeight(){return weight;}

        //note: possible not to provide a name here with your prototypes
        //ex: void SetAll(std::string, double, double);
        void SetAll(std::string name, double height, double weight);

        Animal(std::string name, double height, double weight); //<constructor
        Animal(); //<overload constructor when no attributes are passed
        ~Animal(); //<deconstructor

        void ToString();
};

int Animal::numOfAnimals = 0;

void Animal::SetAll(std::string name, double height, double weight){
    this->name = name;
    this->height = height;
    this->weight = weight;
}
//constructor
Animal::Animal(std::string name, double height, double weight){
    this->name = name;
    this->height = height;
    this->weight = weight;
    Animal::numOfAnimals++;
}
//overload constructor when no attributes are passed
Animal::Animal(){
    this->name = "";
    this->height = 0;
    this->weight = 0;
    Animal::numOfAnimals++;
}
//destructor
Animal::~Animal(){ std::cout << "Animal " << this -> name << " destroyed\n";}

void Animal::ToString(){
    std::cout << this -> name << " is "
              << this -> height << " cms tall and "
              << this -> weight << " kgs in weight\n";
}

// # Dog ..................................................
class Dog: public Animal{
    private:
        std::string sound = "woof";
    public:
        void MakeSound(){ printf("The dog %s says %s\n", this->GetName().c_str(), this->sound.c_str());}
        Dog(std::string name, double height, double weight, std::string sound);
        Dog(): Animal(){};
        void ToString();
};

Dog::Dog(std::string name, double height, double weight, std::string sound) :
Animal(name, height, weight){
    this->sound = sound;
}

void Dog::ToString(){
    //printf("%s is %d cms tall and %d kgs in weight and says %s\n",
    //        this->GetName().c_str(), this->GetHeight(), this->GetWeight(), this->sound.c_str());
    // note: do not work well with this->GetHeight() and this->GetWeight()
    std::cout << this -> GetName()   << " is "
              << this -> GetHeight() << " cms tall and "
              << this -> GetWeight() << " kgs in weight and says "
              << this -> sound       << "\n";
}

// END CLASS ----------------------------------------------

int main (int argc, char** argv) {
    //create 1st animal - fred
    Animal fred;
    //test overloaded constructor
    fred.ToString();
    //add attributes value of 1st animal - Fred
    fred.SetHeight(33);
    fred.SetWeight(10);
    fred.SetName("Fred");
    fred.ToString();
    //create 2nd animal using constructor - tom
    Animal tom("Tom", 36, 15);
    tom.ToString();
    //create 1st dog - spot
    Dog spot("Spot", 38, 16, "woofWoof");
    //print 2nd dog info
    spot.ToString();
    spot.MakeSound();
    //print number of animal
    std::cout << "Number of Animals : " << Animal::GetNumOfAnimals() << "\n";
    return 0;
}

代码的预期和当前输出:

可能最好的地方不在这里,而是在 https://codereview.stackexchange.com/ 上(仅用于代码)

但是评论很少:

  • 代码和UML模型化是一致的,代码可以无提示编译,太棒了

  • 为什么 A01 : Animal 而不是 fred : AnimalA02 : Animal 而不是 tom : AnimalD01 : Dog 而不是 spot : Dog

  • class图中操作参数的符号不符合UML标准,例如SetName(string name) : void必须是SetName(in name : string) : voidSetName(name : string) : void如果隐藏方向

  • 我鼓励您尽可能多地使用 const 操作,例如对于 getters (GetName, GetHeight ...)

  • 在没有参数的构造函数中你不需要做this->name = "";,幸运的是std::string作为一个空字符串的构造函数

  • Animal::ToString()Dog::ToString() dodoes not make a string, iteyt write on stdout, their names are misising

  • 你声明了析构函数但没有定义它们

  • 因为 Animal 是一个基础 class 把它的 destructor virtual。如果您从 Animal 的指针中删除一个实例,而实际上它是一个子 class 的实例,则需要这样做。您错过了在其中递减 numOfAnimals

  • 最好有 ToString virtual 来调用版本取决于实例的真实类型而不是比编译时已知的类型。在main中加入{ Animal * a = &spot; a->ToString(); },看结果

  • 为什么要在 MakeSound() 中使用 printf

  • 你允许实例化Animal,这是一个可以接受的选择,另一个是太使class抽象只允许实例化子class与有效动物相关

  • 我个人只使用大写字符作为操作(和属性)名称的开头,当它是 static 时,可以区分它们。

P.S。考虑你在 S.O 上的照片。我很惊讶没有猴子class ;-)