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
实际上没有继承,那么您的wrapping
Cow
将继承
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;
};
}