如何创建一个继承特定基类的任何一个子类的类

时间:2016-10-15 17:42:08

标签: c++ oop

如果之前已经回答过,我很抱歉,但我一直在寻找好几个小时。这是我想要做的一个人为的例子。

#include <iostream>

using namespace std;

int main(void);

class humanoid {
public:
        int humanoid_attribute;
        virtual void do_something_to_any_humanoid(void) = 0;
};

class man: public humanoid {
public:
        int man_attribute;
        void do_something_to_any_humanoid(void) { cout << "Doing something to a man which is a humanoid.\n"; }
};

class cat {
public:
        int cat_attribute;
        virtual void do_something_to_any_cat(void) = 0;
};

class lion : public cat {
public:
        int lion_attribute;
        void do_something_to_any_cat(void) { cout << "Doing something to a lion which is a cat.\n"; }
};

class sphinx : public humanoid, public cat {
public:
        int sphinx_attribute;
        sphinx(humanoid & humanoidIn, cat & catIn) : humanoid(humanoidIn), cat(catIn) { }
};

int main(void) {
        man myMan;
        lion myLion;

        sphinx mySphinx(myMan, myLion);
        mySphinx.do_something_to_any_humanoid();
}

问题在于,当实例化sphinx时,我会收到以下错误:

./main.cpp: In function ‘int main()’:
./main.cpp:41:9: error: cannot declare variable ‘mySphinx’ to be of abstract type ‘sphinx’
  sphinx mySphinx(myMan, myLion);
         ^
./main.cpp:31:7: note:   because the following virtual functions are pure within ‘sphinx’:
 class sphinx : public humanoid, public cat {
       ^
./main.cpp:22:15: note:     virtual void cat::do_something_to_any_cat()
  virtual void do_something_to_any_cat(void) = 0;
               ^
./main.cpp:10:15: note:     virtual void humanoid::do_something_to_any_humanoid()
  virtual void do_something_to_any_humanoid(void) = 0;

我理解错误的内容,但无法找出正确的方法。我确实对此有用,是的,&#39; sphinx&#39;是某种类人生物和某种猫科动物,应该继承它们的所有属性和方法。此外,该男子&#39;和狮子&#39;需要是孩子,所以我可以做一个丑陋的狮身人面像。你能想象一个克林贡人和一个波斯人吗?

3 个答案:

答案 0 :(得分:2)

继承表达is-a关系。

如果sphinx同时属于humanoidcat,则该类型必须能够在humanoid或{{1}的所有上下文中使用}} 是必须的。由于这两种类型有两种纯cat方法,因此必须为这些方法提供实现。

答案 1 :(得分:0)

首先,我们应该看看你尝试实现的目标:抽象基类作为非抽象叶类对象可以分派的蓝图方法的接口。

为此,我们将类变量保留在其中,并专注于仅使用类方法的示例:

#include <iostream>

/* astract base classes */
/* -------------------- */
class Humanoid {
public:
  virtual ~Humanoid() = 0;
    // Pure virtual; ensures Humanoid is abstract, even in case we supply
    // default implementations for all "blueprinted" method (not the case
    // for the Humanoid type, but for the Cat type)

  // no default implementation supplied: derived classes
  // must implement this method in order to be non-abstract
  virtual void doSomethingToAnyHumanoid() = 0;
};
Humanoid::~Humanoid() {}

class Cat {
public:
  virtual ~Cat() = 0; // Pure virtual; ensures Cat is abstract ...

  // supply a default implementation
  virtual void doSomethingToAnyCat() {
    std::cout << "Cat default implementation\n";
  }
};
Cat::~Cat() {}

这两个基类是抽象的,因为它们至少有一个纯虚方法(在Cat的情况下,只有它的DTOR)。

作为第一次尝试,我们将尝试实现一个sphinx类,它是常见的叶子类Humanoid以及Cat

/* non-abstract leaf classes */
/* ------------------------- */
class NotReallyASphinx : public Humanoid, public Cat {
public:
  // by choice (not necessity): use default cat implementation

  // for non-abstractness: implement custom Humanoid implementation
  virtual void doSomethingToAnyHumanoid() override {
    std::cout << "Needs to be done on four legs ...\n";
  }
};

/* example usage */
int main() {
  NotReallyASphinx notReallyASphinx;
  notReallyASphinx.doSomethingToAnyHumanoid(); // Needs to be done on four legs ...
  notReallyASphinx.doSomethingToAnyCat();      // Cat default implementation

  return 0;
}

由于Humanoid没有提供doSomethingToAnyHumanoid的默认实现,因此我们必须在NotReallyASphinx中实现它,以便后者不是抽象的。

现在,对于你在狮身人面像上的类似狮身人面像的尝试,似乎你想要使用LionMan实例(但是,在它们的抽象基础的地址中包装)类)构建UglySphinx的基础。让我们首先实现最小的非抽象类型LionMan

/* non-abstract leaf classes */
/* ------------------------- */
class Man: public Humanoid {
public:
  virtual void doSomethingToAnyHumanoid() override {
    std::cout << "Doing something to a man which is a humanoid.\n";
  }
};

class Lion : public Cat {
public:
  virtual void doSomethingToAnyCat() override {
    std::cout << "Doing something to a lion which is a cat.\n";
  }
};

但是,如果您想根据上述两种类型的实例构建UglySphinx,则需要使用类型合成:where和UglySphinx实例本身拥有LionMan的实例(责任)。

/* non-abstract leaf classes */
/* ------------------------- */
class UglySphinx : public Humanoid, public Cat {
private:
  Humanoid& m_humanoid;
  Cat& m_cat;
    // we know that humanoidIn and catIn will persist at least
    // as long as the UglySphinx instance, so we'll just work
    // on the stack for this example. An alternative is using
    // pointers here and working on heap; which includes responsibility
    // handling of the heap objects (e.g. owned by UglySphinx)

public:
  UglySphinx(Humanoid& humanoidIn, Cat& catIn) : m_humanoid(humanoidIn), m_cat(catIn) { }

  // by choice (not necessity): use dynamic dispatch to use the
  // m_cat(lion) implementation
  virtual void doSomethingToAnyCat() override {
    m_cat.doSomethingToAnyCat();
  }
  // for non-abstractness: we must implement custom Humanoid implementation,
  // but as above, use m_humanoid(man) for this purpose
  virtual void doSomethingToAnyHumanoid() override {
    m_humanoid.doSomethingToAnyHumanoid();
  }
};

这将允许我们使用UglySphinxMan对象构建Lion

/* example usage */
int main() {
  Man aMan;
  Lion aLion;
  UglySphinx uglySphinx(aMan, aLion);

  uglySphinx.doSomethingToAnyHumanoid(); // Doing something to a man which is a humanoid.
  uglySphinx.doSomethingToAnyCat();      // Doing something to a lion which is a cat.

  return 0;
}

由于您打算使用抽象基类类型的地址(替代指针),上面的UglySphinx类型将允许我们基于创建一个(真正的)UglySphinx实例例如一个Man个实例,例如RagDoll

/* non-abstract leaf classes */
/* ------------------------- */
class RagDoll : public Cat {
public:
  virtual void doSomethingToAnyCat() override {
    std::cout << "Doing something to a ragdoll which is a cat.\n";
  }
};

/* example usage */
int main() {
  Man aMan;
  RagDoll aRagdoll;
  UglySphinx reallyUglySphinx(aMan, aRagdoll);

  reallyUglySphinx.doSomethingToAnyHumanoid(); // Doing something to a man which is a humanoid.
  reallyUglySphinx.doSomethingToAnyCat();      // Doing something to a ragdoll which is a cat.

  return 0;
}

我无法看到创建基于布娃娃的Sphinx的风险是有意的,所以也许您真正想做的是创建PersistantUglySphinx,保证由Man组成Lion个实例(分别是方法doSomethingToAnyHumanoid()doSomethingToAnyCat())?

/* non-abstract leaf classes */
/* ------------------------- */
class PersistantUglySphinx : public Man, public Lion {
private:
  Man m_man;
  Lion m_lion;

public:
  PersistantUglySphinx(Man& manIn, Lion& lionIn) : m_man(manIn), m_lion(lionIn) { }

  virtual void doSomethingToAnyCat() override {
    m_lion.doSomethingToAnyCat();
  }

  virtual void doSomethingToAnyHumanoid() override {
    m_man.doSomethingToAnyHumanoid();
  }
};

请注意,通过这种方法,我们遇到了可能的最佳实践问题。由于PersistantUglySphinx派生自ManLion,后两种类型不再是叶类,而是它们也不是抽象的。特别是在使用&#34; interface&#34; -like继承时,如本示例所示,我至少亲自尝试遵守Scott Meyers的建议,我们应该&#34; Make non-leaf classes abstract&#34; (来自&#34的项目33;更有效的C ++&#34; )。

包装起来:确保理解抽象类是什么,以及从抽象类派生的类是非抽象的(即,抽象基类的所有纯虚方法的实现)

答案 2 :(得分:0)

@dfri:我的意图是这样的代码:

#include <iostream>
using namespace std;

int main(void);

class Humanoid {
private:
        int HumanoidAttribute;

public:
        // pure virtual to ensure all derived classes define it
        virtual void doSomethingToAnyHumanoid(void) = 0;

        // pure virtual to ensure this is an abstract class
        // not really necessary because doSomethingToAnyHumanoid is pure virtual but good practice
        virtual ~Humanoid() = 0;
};
Humanoid::~Humanoid() { }

class Man: public Humanoid {
private:
        int ManAttribute;
public:
        void doSomethingToAnyHumanoid(void) override {
                cout << "Doing something to a Man which is a Humanoid.\n";
        }
};

class Cat {
private:
        int CatAttribute;
public:
        // pure virtual to ensure all derived classes define it
        virtual void doSomethingToAnyCat(void) = 0;

        // pure virtual to ensure this is an abstract class
        // not really necessary because doSomethingToAnyCat is pure virtual but good practice
        virtual ~Cat() = 0;
};
Cat::~Cat() { }

class Lion : public Cat {
private:
        int LionAttribute;
public:
        void doSomethingToAnyCat(void) override {
                cout << "Doing something to a Lion which is a Cat.\n";
        }
};

class Sphinx : public Humanoid, public Cat {
private:
        Humanoid & m_Humanoid;
        Cat & m_Cat;
        int SphinxAttribute;
public:
        Sphinx(Humanoid & HumanoidIn, Cat & CatIn) : m_Humanoid(HumanoidIn), m_Cat(CatIn) { }
        void doSomethingToAnyHumanoid(void) { m_Humanoid.doSomethingToAnyHumanoid(); }
        void doSomethingToAnyCat(void) { m_Cat.doSomethingToAnyCat(); }
};

int main(void) {
        Man myMan;
        Lion myLion;

        Sphinx mySphinx(myMan, myLion);
        mySphinx.doSomethingToAnyHumanoid();
}

由于基类的方法是纯虚拟的,所以在编译Sphinx类时我应该注意,如果我错过了一些包装器方法。

有人有任何其他意见吗?我是C ++的新手,所以欢迎任何提示!