如果之前已经回答过,我很抱歉,但我一直在寻找好几个小时。这是我想要做的一个人为的例子。
#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;需要是孩子,所以我可以做一个丑陋的狮身人面像。你能想象一个克林贡人和一个波斯人吗?
答案 0 :(得分:2)
继承表达is-a关系。
如果sphinx
同时属于humanoid
和cat
,则该类型必须能够在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
中实现它,以便后者不是抽象的。
现在,对于你在狮身人面像上的类似狮身人面像的尝试,似乎你想要使用Lion
和Man
实例(但是,在它们的抽象基础的地址中包装)类)构建UglySphinx
的基础。让我们首先实现最小的非抽象类型Lion
和Man
:
/* 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
实例本身拥有Lion
和Man
的实例(责任)。
/* 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();
}
};
这将允许我们使用UglySphinx
和Man
对象构建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
派生自Man
和Lion
,后两种类型不再是叶类,而是它们也不是抽象的。特别是在使用&#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 ++的新手,所以欢迎任何提示!