实现基类方法以访问派生类的属性

Posted

技术标签:

【中文标题】实现基类方法以访问派生类的属性【英文标题】:implement a base class method to access a property of derived classes 【发布时间】:2013-08-30 06:33:59 【问题描述】:

我有一个基类和几个可以有多个实例的派生类。 派生类有一个静态字符串,其中存储了国籍名称。 看起来像这样……

// Base Class
class Person
    private:
        // Informations that every person has. Not depending on the nationality
        unsigned char m_size;
        char[] m_name;

    public:
        // Get the human readable name of a nationality
        void getNationalityName(char* pNatiName);


void Base::getNationalityName(char* pNatiName);

    strcpy(pNatiName, m_nationalityName);



// A derived class
class American : public Person
    private:
        unsigned int m_dollar;
        static char[] m_nationalityName;


// Another derived class
class Russian : public Person
    private:
        unsigned int m_rubel;
        static char[] m_nationalityName;

我现在想使用派生类之一的“getNationalityName”方法访问国籍名称。 问题是,基类不知道派生类有一个名为“m_nationalityName”的属性。

我可以在每个类中实现“getNationalityName”方法,但我认为这不是解决这个问题的正确方法。

【问题讨论】:

【参考方案1】:

不要。设计看起来有缺陷。国籍应该是一个人的财产(即数据成员)。如果有人有2个国籍怎么办?

enum Nationality

   ROMANIAN,
   AMERICAN,
   RUSSIAN,
;

class Person

   Nationality nationality; // or std::vector<Nationality> nationalities;
;

枚举值之后可以很容易地转换。

【讨论】:

我认为 OP 想要一个字符串表示来打印出来,或者类似的东西...... @SingerOfTheFall 随后的转换是微不足道的。我的主要观点是没有那个类层次结构。 是的,这是真的。这也只是我的一个例子,没有人可以有两个国籍,很抱歉造成混淆:)【参考方案2】:

使用多态性。使您的getNationalityName 函数virtual,并在派生类中重新定义它以返回所需的字符串。每次都会调用派生类的函数,返回对应类的字符串:

//base class:
class Person
    <...>

    public:
        virtual void getNationalityName(char* pNatiName);


<...>

// A derived class
class American : public Person
    public:
        void getNationalityName(char* pNatiName)
        
            strcpy(pNatiName, m_nationalityName);
        
    private:
        unsigned int m_dollar;
        static char[] m_nationalityName;


<...>

int main()

    Person * p = new American();
    p->getNationalityName(<...>); // calls American::getNationalityName name even though p is a pointer to the base class.

【讨论】:

似乎是一个不错的解决方案。谢谢你:)【参考方案3】:

听起来像m_nationalityName 应该放在你的基类person 中。对我来说,国籍更像是person的一个属性。只是不要让它static,因为你不想让所有的人都拥有相同的国籍。

【讨论】:

是的,我也想过这个...但是所有的人都会有相同的国籍,不是吗?还是每个派生类都会有一个新的静态属性实例? 我认为每个民族都应该是一个类,因为每个民族都会有其他不同的属性和方法 好的。如果这是真的,您可以做的一件事是为国籍创建一个新类,并使用组合模式,即让国籍成为您的 Person 类的成员。【参考方案4】:

我认为这种情况可以这样处理。因为不同国籍只是名称不同,行为不同,所以不需要使用多态性

  class Nationality
  
  private:
        Nationality(const char* name_i):m_name(name_i)
        
        
        const char * m_name;
  public:
        static Nationality& American()
        
             static Nationality country("American");
             return country;
        

        static Nationality& Russian()
        
             static Nationality country("Russia");
        

        void getName(char* pNatiName) const
        
            strcpy(pNatiName, m_name);
        

   ;


   class Person
   
   private:
        <................>
        Nationality* nationality

   public:
       void getNationalityName(char* pNatiName)const
       
             nationality->getName(pNatiName);
       

   ;

【讨论】:

【参考方案5】:

使用Curiously recurring template pattern,您可以这样做:

template<class T>
class Person 
    static const std::string m_nationalityName;

    // ...
;

template<class T> const std::string Person<T>::m_nationalityName = "Unknown";

class American : public Person<American> 
    // ...
;

template<> const std::string Person<American>::m_nationalityName = "American";

class Russian : public Person<Russian> 
    // ...
;

template<> const std::string Person<Russian>::m_nationalityName = "Russian";

不适用于char[]

【讨论】:

-1 一方面,它不是解决给定问题的好方法,因为美国人不再是人。其次,它完全适用于 char[] 我尝试使用char[],它无法编译,因为字符串的长度不同。我不明白美国人怎么不再是人了。 美国人不是人,而是人。您不再拥有多态 Person 基类。 嗯,你当然可以将它拆分成一个多态的Person 和一个模板化的PersonWithNationality,或者使用一个traits 结构。我只是想演示如何为每个派生类定义具有不同值的静态类字段。

以上是关于实现基类方法以访问派生类的属性的主要内容,如果未能解决你的问题,请参考以下文章

5继承与派生2-访问控制

如果派生类作为基类返回,如何访问派生类的方法?

从基类类型的向量访问派生类方法

详解C++中基类与派生类的转换以及虚基类

C#关键字学习

虚基类菱形派生关系