如何在 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;
}
代码的预期和当前输出:
- 身高 0 厘米,体重 0 公斤
- 弗雷德身高 33 厘米,体重 10 公斤
- 汤姆身高 36 厘米,体重 15 公斤
- Spot 身高 38 厘米,体重 16 公斤,说 woofWoof
- 狗狗 Spot 说 woofWoof
- 动物数量:3
- Animal Spot 被摧毁
- 动物汤姆被摧毁
- 动物弗雷德被摧毁
可能最好的地方不在这里,而是在 https://codereview.stackexchange.com/ 上(仅用于代码)
但是评论很少:
代码和UML模型化是一致的,代码可以无提示编译,太棒了
为什么 A01 : Animal
而不是 fred : Animal
,A02 : Animal
而不是 tom : Animal
,D01 : Dog
而不是 spot : Dog
?
class图中操作参数的符号不符合UML标准,例如SetName(string name) : void
必须是SetName(in name : string) : void
或SetName(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 ;-)
我正在使用 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;
}
代码的预期和当前输出:
- 身高 0 厘米,体重 0 公斤
- 弗雷德身高 33 厘米,体重 10 公斤
- 汤姆身高 36 厘米,体重 15 公斤
- Spot 身高 38 厘米,体重 16 公斤,说 woofWoof
- 狗狗 Spot 说 woofWoof
- 动物数量:3
- Animal Spot 被摧毁
- 动物汤姆被摧毁
- 动物弗雷德被摧毁
可能最好的地方不在这里,而是在 https://codereview.stackexchange.com/ 上(仅用于代码)
但是评论很少:
代码和UML模型化是一致的,代码可以无提示编译,太棒了
为什么
A01 : Animal
而不是fred : Animal
,A02 : Animal
而不是tom : Animal
,D01 : Dog
而不是spot : Dog
?class图中操作参数的符号不符合UML标准,例如
SetName(string name) : void
必须是SetName(in name : string) : void
或SetName(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 ;-)