Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何初始化祖父母';C+中孙子的s(const)财产+;? 我知道这看起来像是一个小问题,但我没有找到真正的C++解决方案来解决以下问题。_C++_Initialization - Fatal编程技术网

如何初始化祖父母';C+中孙子的s(const)财产+;? 我知道这看起来像是一个小问题,但我没有找到真正的C++解决方案来解决以下问题。

如何初始化祖父母';C+中孙子的s(const)财产+;? 我知道这看起来像是一个小问题,但我没有找到真正的C++解决方案来解决以下问题。,c++,initialization,C++,Initialization,我想表示对象“世界”的复杂(树状)层次结构。比如说动物。每种动物都有一些基本的常量属性。 例如一个名称。然后它也有一些方法,但是它们对于这个问题没有意义 class Animal { public: const char *GetName() const; protected: const char *name; }; class Insect : public Animal { ... }; class Butterfly : public Insect {

我想表示对象“世界”的复杂(树状)层次结构。比如说
动物
。每种动物都有一些基本的常量属性。 例如一个
名称
。然后它也有一些方法,但是它们对于这个问题没有意义

class Animal {
public:
    const char *GetName() const;

protected:
    const char *name;
};

class Insect : public Animal {
    ...
};

class Butterfly : public Insect {
    ...
};
在这个层次结构中,我想在每个派生(grand)子级中初始化
名称
什么是优雅的解决方案?

同样重要的是,在这个“世界”中,只有树叶的例子。也就是说,不会有“动物”或“昆虫”的物体。但会有“蝴蝶”、“蜜蜂”或“蚊子”这样的物体

我知道这样做的“标准”方法是将
name
放入构造函数:

Animal::Animal(const  char *name) : name(name) {}
Insect::Insect(const  char *name) : Animal(name) {}
Butterfly::Butterfly() : Insect("Butterfly") {}
class Animal {
public:
    const char *GetName() const;

protected:
    std::string name;
};

Horse::Horse() {this->name = "Horse";}
但是,如果这些属性更多,则派生类也需要一些初始化,并且层次结构具有更多级别,因此可能会变得非常混乱:

Animal::Animal(const  char *name) : name(name) {}
Vertebrate::Vertebrate(const  char *name) : Animal(name) {}
Mammals::Mammals(const  char *name) : Vertebrate(name) {}
Ungulate::Ungulate(const  char *name) : Mammals(name) {}
Horse::Horse() : Ungulate("Horse") {}
我可以看到的另一个选项是删除
常量
,直接在孙子的构造函数中赋值:

Animal::Animal(const  char *name) : name(name) {}
Insect::Insect(const  char *name) : Animal(name) {}
Butterfly::Butterfly() : Insect("Butterfly") {}
class Animal {
public:
    const char *GetName() const;

protected:
    std::string name;
};

Horse::Horse() {this->name = "Horse";}
但这也不是最优的,因为常量丢失并且更容易出错(初始化可能会被忘记)


是否有更好的方法可以做到这一点?

您的备选方案或任何保留
name
非常量且受保护的备选方案的问题在于,无法保证子类会正确设置此属性

下面的课程给你什么

class Animal {
public:
    Animal(const char* something)
    const char *GetName() const;

private:
    const char *name;
};
保证动物接口的不变性,这在执行多线程时是一个很大的优势。如果一个对象是不可变的,那么多个线程可以使用它,而不是关键资源

我知道这样做的“标准”方法是在构造函数中输入名称: ... 但如果这些属性更多,则派生类 还需要一些初始化,层次结构可以有更多的级别 一团糟


一点也不乱。假设只有一个地方初始化对象A的成员,并且它位于其子类的构造函数中

Hm-希望我不会因为这个答案而被SO锁定,但是您可以使用一个实现
name
-属性的虚拟基类。因此,您不必在整个层次结构中传播基类中的初始化,而是可以使用
name
-属性直接寻址“非常基本”的构造函数。此外,实际上,您将被迫在任何“孙子”类中调用它,因此您不会意外地忘记它:

class NamedItem {
public:
    NamedItem(const char* _name) : name(_name) {}
    const char *GetName() const;

protected:
    const char *name;
};

class Animal : public virtual NamedItem {
public:
    Animal(int mySpecificOne) : NamedItem("") {}
};

class Insect : public Animal {
public:
    Insect(int mySpecificOne) : Animal(mySpecificOne), NamedItem("") {}

};

class Butterfly : public Insect {
};

优雅的解决方案是通过初始化传递参数。例如,如果“name”变量是蝴蝶的名字(例如“sally”或“david”),那么很明显,它必须通过初始化来完成。如果您发现这很难看,就像这里一样,这可能表明您的数据分解/类继承权有问题。在您的示例中,每个Butterfly对象都有一组完全相同的属性,它们真正引用的是它们的类而不是每个实例,即它们是类变量而不是实例变量。这意味着“Butterfly”类应该有一个指向公共“昆虫”对象的静态指针(可能有一个指向单个“动物”对象等的指针)或一组重写的虚拟函数。(下面我只展示了一个等级的继承权,但你应该能够计算出更多等级)

//使虚拟继承的功能纯虚拟
类动物{
私人:
std::string objName;//每个对象实例数据
公众:
虚拟~Animal(std::string n):对象名(n){}
虚拟std::string const&getName()=0;//每个子类数据访问
虚拟std::string const&getOrder()=0;//每个子类数据访问
std::string const&getObjName(){返回此->objName;}
};
//将公共数据放入非继承类
动物类{
私人:
std::字符串名;
公众:
动物名称(std::string n):名称(n);
std::string const&getName()const{返回此->名称;}
};
//继承每个实例的功能,包含每个类的数据。
蝴蝶类:公共动物{
私人:
静态std::unique昆虫;//子类数据
公众:
蝴蝶(std::string n):动物(n){}
虚拟~Butterfly(){}
虚拟std::string const&getName()重写{
返回此->昆虫->获取名称();}
虚拟std::string const&getOrder()重写{
静态标准::字符串顺序(“鳞翅目”);
退货单;}
};
//类特定的数据现在在实现文件中初始化一次。
独特的蝴蝶昆虫(新的动物蝴蝶);
现在使用Butterfly类只需要每个实例的数据

Butterfly b( "sally" );
std::cout << b.getName() << " (Order " << b.getOrder() 
          << ") is called " << b.getObjName() << "\n";
蝴蝶b(“莎莉”);
std::cout您的数据成员实际上不是
const
。这会改变你的推理吗?@juanchopanza它不会:-)从
动物的角度来看,你在技术上是对的,它不是常数。但从逻辑的角度来看,这个“世界”的每一个对象都是常量。我还可以将
const char*name
Animal
移动到叶子中,在那里它将是const。但这在我看来更难看。我认为@juanchopanza的意思是
const char*
只是指向不可变
char
数组的指针;但是指针本身是可变的。对于真正的不变性,它将是
const char*const
——这意味着该值只能在构造时设置,并且在这是正确答案之后不能更改。使用构造函数进行初始化没有错;这正是他们在那里的目的。尽管很迂腐:
name
在技术上并不是一成不变的,因为指针可以更改;只是地方检察官