C++ C++;从抽象基类派生的包装类,并在另一个也从抽象基类派生的类中调用方法
我有一个名为C++ C++;从抽象基类派生的包装类,并在另一个也从抽象基类派生的类中调用方法,c++,inheritance,abstract-class,wrapper,C++,Inheritance,Abstract Class,Wrapper,我有一个名为Animal的抽象类和一个名为cow的派生类 Cow提供了Animal中纯虚拟函数的定义 我想创建一个名为AnimalWrapper的类,该类继承自Animal。我希望方法AnimalWrapper.speak()只需调用cow.speak() 我是否只需要引用animalwrapper类中的cow对象,以便调用非静态方法speak 我该怎么做 #include<iostream> #include<cstdlib> using namespace
Animal
的抽象类和一个名为cow
的派生类
Cow
提供了Animal
中纯虚拟函数的定义
我想创建一个名为AnimalWrapper
的类,该类继承自Animal
。我希望方法AnimalWrapper.speak()
只需调用cow.speak()
我是否只需要引用animalwrapper类中的cow
对象,以便调用非静态方法speak
我该怎么做
#include<iostream>
#include<cstdlib>
using namespace std;
#include <string>
class Animal // This Animal is an abstract base class
{
public:
Animal(){};
virtual const char* speak() = 0; //pure virtual function
};
class Cow: public Animal
{
public:
Cow(){};
virtual const char* speak() {
cout << "I am a cow" << endl;
return "Moo ";
}
};
class AnimalWrapper: public Animal
{
public:
AnimalWrapper(){}
virtual const char* speak() {
cout << "Calling cow class speak() method" << endl;
//Call Cow::speak()
return "Moo";
}
};
int main()
{
AnimalWrapper AnimalWrapper_obj ;
std::cout << AnimalWrapper_obj.speak() << '\n';
}
#包括
#包括
使用名称空间std;
#包括
class Animal//此动物是一个抽象基类
{
公众:
动物{};
虚常量char*speak()=0;//纯虚函数
};
牛类:公共动物
{
公众:
奶牛{};
虚拟常量字符*speak(){
cout根据您的评论,这里有一个类AnimalWrapper使用move semantic获取Cow实例的外部引用的示例。由于它是一个移动构造函数而不是复制构造函数,所以在使用原始对象时应小心
如果您想保留Cow的原始实例,那么您可能需要一个副本构造函数(但您将复制Cow实例)
您也可以将指针或引用存储在类Cow*cowInstance
或Cow&cowInstance
)中,但最终可能会出现悬空指针/引用(因此我在这里使用移动语义)
#包括
#包括
#包括
//使用namespace std;//假设您希望扩展正在使用的API,但无法修改它本身,我认为您希望提供一个并行层次结构:
namespace wrapped
{
class Animal
{
public:
virtual ~Animal();
virtual std::string speak();
};
class Cow : public Animal
{
public:
std::string speak() override;
unsigned int giveMilk() { return 77; }
};
}
namespace wrapping
{
class Animal
{
protected:
wrapped::Animal& animal;
Animal(wrapped::Animal& animal)
: animal(animal)
{ }
public:
virtual ~Animal() { }
// does not need to be virtual, we can profit from
// polymorphism of referred object...
//
// still it CAN be virtual, if you want to allow derived
// wrappers as well to modify the inherited speak!
std::string speak()
{
return animal.speak();
}
};
class Cow : public Animal
{
public:
Cow(wrapped::Cow& cow)
: Animal(cow)
{ }
// speak is inherited
unsigned int giveMilk()
{
// don't need dynamic cast as we passed a reference
// to cow object to base class constructor...
return static_cast<wrapped::Cow&>(animal).giveMilk();
}
};
}
但是,如果Cow
实际上没有继承,那么您的wrappingCow
将继承wrapped::Animal
的两个实例,这将导致许多问题暂时不在这里讨论
但是,如果在wrapping::animal
中重写speak
,则需要在wrapping::Cow
中提供最终重写器,以解决speak
的两个继承重写变体之间的歧义
实际上,您可以公开地从包装的基继承,这样您就不再需要使用声明了(不过,最终的重写器问题仍然存在),但这将允许wrapped类和wrapping类之间的混合,这是您最想防止的。是什么阻止您从Cow
而不是Animal
派生Cow::speak()
呢(或者根本不重写它)…我对你为什么需要包装器很好奇?它设计用来解决什么问题?至于你的问题,如果你想对一个对象调用一个非静态成员函数,你需要该对象的一个实例。也许包装器类应该通过组合包含一个包装对象的实例(否则它现在不是什么包装物了,是吗?;))你有一个牛包装物,它是动物,但它不是牛。你的代码中没有牛。哪头牛应该说话()?你可以在CowWrapper::speak(){return Cow().speak();}中创建一头新的牛
您的请求非常接近于常见的设计模式,如适配器、桥接器,尤其是抽象工厂(即,以后您可能不仅希望cows,还希望其他人也能说话)。事实上,输入了一个输入错误(CowWrapper而不是Cow表示构造函数名称,此外,包装
名称空间尚未关闭).实际上,您应该通过检查编译器的错误消息来轻松发现自己。学习理解这些错误消息将在将来为您带来很多麻烦,并且可能会有很多问题,所以…感谢您的友好解释。这就是我想要理解的。移动语义对我来说有点太高级了,尽管我有点不懂了解你在做什么。如果你想看到你在类中存储引用的同一个例子,那会不会太过分。我想理解的是,你会称之为speak()AnimalWrapper
类中存储的Cow&cowInstance
上的方法。然后我将继续移动语义。谢谢存储引用的问题是,您要么存储对外部Cow
对象的引用,而您不控制该对象的生存期,否则您的程序可能会因发生错误而崩溃悬空引用(对已删除对象的引用)。或者您必须复制Cow
对象,但随后您有两个独立的Cow
实例。
namespace wrapped
{
class Animal
{
public:
virtual ~Animal();
virtual std::string speak();
};
class Cow : public Animal
{
public:
std::string speak() override;
unsigned int giveMilk() { return 77; }
};
}
namespace wrapping
{
class Animal
{
protected:
wrapped::Animal& animal;
Animal(wrapped::Animal& animal)
: animal(animal)
{ }
public:
virtual ~Animal() { }
// does not need to be virtual, we can profit from
// polymorphism of referred object...
//
// still it CAN be virtual, if you want to allow derived
// wrappers as well to modify the inherited speak!
std::string speak()
{
return animal.speak();
}
};
class Cow : public Animal
{
public:
Cow(wrapped::Cow& cow)
: Animal(cow)
{ }
// speak is inherited
unsigned int giveMilk()
{
// don't need dynamic cast as we passed a reference
// to cow object to base class constructor...
return static_cast<wrapped::Cow&>(animal).giveMilk();
}
};
}
namespace wrapping
{
class Animal : private virtual wrapped::Animal
{
public:
using wrapped::Animal::speak;
};
class Cow : public Animal, private wrapped::Cow
{
public:
using wrapped::Cow::speak;
};
}