Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 返回抽象类的实例而不进行切片_Java_C++_Abstract - Fatal编程技术网

Java 返回抽象类的实例而不进行切片

Java 返回抽象类的实例而不进行切片,java,c++,abstract,Java,C++,Abstract,有没有一种方法可以返回函数中抽象类的不同变体,而不会因切片而丢失信息 比如说,我有一个抽象的类狗,对于狗来说有野狗,家养狗,小狗 是否可以创建一个函数,该函数接受其中一个函数并返回它们,而无需切片信息 例如: // Returns the type of dog you currently have Dog getCurrentDog() { return this.dog; } void setDog(Dog dog) { this.dog = dog; } 是否可以将Wi

有没有一种方法可以返回函数中抽象类的不同变体,而不会因切片而丢失信息

比如说,我有一个抽象的类狗,对于狗来说有野狗,家养狗,小狗

是否可以创建一个函数,该函数接受其中一个函数并返回它们,而无需切片信息

例如:

// Returns the type of dog you currently have
Dog getCurrentDog() {
    return this.dog;
}

void setDog(Dog dog) {
    this.dog = dog;
}
是否可以将WildDog或PuppyDog传递给setDog并保留相应类中的所有信息。例如,PuppyDog有一个其他狗没有的drinkMilk()函数,但我仍然希望能够访问它

如果可能的话,Java的等价物是什么


我现在正在考虑的解决方案是为每个Dog实例设置一个getDog(),该实例返回特定的Dog实例,无论是Puppy还是WildDog。这样,我可以专门访问每个类中的代码。

为了避免切片,您需要向
狗传递指针或引用。看

现在,您可以拥有以下功能:

 // getCurrentDog is a PuppyDog
 std::shared_ptr<Dog> myDog = someOwner.getCurrentDog();
 myDog->drinkMilk();

正如@PaulMcKenzie指出的,这通常是一个设计缺陷,并偏离了面向对象编程(因为最终会出现“如果它是
野狗
,那么就这样做;如果它是
小狗
,那么就这样做”等)

为了避免切片,你需要向
传递一个指针或引用。看

现在,您可以拥有以下功能:

 // getCurrentDog is a PuppyDog
 std::shared_ptr<Dog> myDog = someOwner.getCurrentDog();
 myDog->drinkMilk();

正如@PaulMcKenzie所指出的,它通常是一个设计缺陷,并偏离了面向对象编程(因为最终会出现“如果它是一个
野狗,那么就这样做;如果它是
pupyDog
,那么就这样做”等)

多态性通常更好地表示为包装类的实现细节。这为您提供了一个异构接口,例如,该接口可以存储在向量中,并且可以在不进行切片的情况下进行复制

我在下面提供了一个工作示例

请注意,各种类型的狗的实现实际上并不是多态的-
dog
puppy
wild\u dog

多态性是作为通用dog类
doggie
的实现细节引入的

#include <iostream>
#include <typeinfo>
#include <memory>
#include <string>
#include <utility>
#include <type_traits>
#include <vector>

// default cases
template<class T>
void do_howl(const T&)
{
    std::cout << "a " << T::dog_type() << " cannot howl" << std::endl;
}

template<class T>
void do_be_cute(const T&)
{
    std::cout << "a " << T::dog_type() << " is not cute" << std::endl;
}


// now provide specialisations
struct dog
{
    dog(std::string s) : name(std::move(s)) {}
    std::string name;
    static const char* dog_type() { return "normal dog"; }
};

void do_howl(const dog& d)
{
    std::cout << "the dog called " << d.name << " is howling" << std::endl;
}


struct puppy
{
    puppy(std::string s) : name(std::move(s)) {}
    std::string name;
    std::string cute_noise() const { return "yip yip!"; }
    static const char* dog_type() { return "puppy"; }
};

void do_be_cute(const puppy& p)
{

    std::cout << "aww! the cute little puppy called " << p.name << " is barking: " << p.cute_noise() << std::endl;
}

struct wild_dog
{

    static const char* dog_type() { return "wild dog"; }
};

void do_howl(const wild_dog& d)
{
    std::cout << "the nameless wild dog called is howling" << std::endl;
}

struct doggy {

    struct concept {

        virtual void be_cute() const = 0;
        virtual void howl() const = 0;

    };

    template<class T>
    struct model : concept
    {
        model(T&& t) : _t(std::move(t)) {}
        model(const T& t) : _t(t) {}

        void be_cute() const override
        {
            do_be_cute(_t);
        }

        void howl() const override
        {
            do_howl(_t);
        }

        T _t;
    };

    void howl() const {
        _impl->howl();
    }

    void be_cute() const {
        _impl->be_cute();
    }

    template<class T, std::enable_if_t<!std::is_base_of<doggy, T>::value>* = nullptr>
    doggy(T&& t) : _impl(std::make_shared<model<T>>(std::forward<T>(t)))
    {}


    std::shared_ptr<concept> _impl;
};

int main()
{
    std::vector<doggy> dogs = {
        doggy(dog("rover")),
        doggy(puppy("poochums")),
        doggy(wild_dog())
    };

    for (const auto& d : dogs)
    {
        d.howl();
        d.be_cute();
    }

    return 0;
}

在这种特殊情况下,
doggie
具有共享的实现语义。如果希望创建不同的副本,请将
共享的\u ptr
替换为
唯一的\u ptr
,提供副本构造函数,并向
概念中添加
克隆()
方法(在
模型中有相应的实现)

多态性通常更好地表示为包装类的实现细节。这为您提供了一个异构接口,例如,该接口可以存储在向量中,并且可以在不进行切片的情况下进行复制

我在下面提供了一个工作示例

请注意,各种类型的狗的实现实际上并不是多态的-
dog
puppy
wild\u dog

多态性是作为通用dog类
doggie
的实现细节引入的

#include <iostream>
#include <typeinfo>
#include <memory>
#include <string>
#include <utility>
#include <type_traits>
#include <vector>

// default cases
template<class T>
void do_howl(const T&)
{
    std::cout << "a " << T::dog_type() << " cannot howl" << std::endl;
}

template<class T>
void do_be_cute(const T&)
{
    std::cout << "a " << T::dog_type() << " is not cute" << std::endl;
}


// now provide specialisations
struct dog
{
    dog(std::string s) : name(std::move(s)) {}
    std::string name;
    static const char* dog_type() { return "normal dog"; }
};

void do_howl(const dog& d)
{
    std::cout << "the dog called " << d.name << " is howling" << std::endl;
}


struct puppy
{
    puppy(std::string s) : name(std::move(s)) {}
    std::string name;
    std::string cute_noise() const { return "yip yip!"; }
    static const char* dog_type() { return "puppy"; }
};

void do_be_cute(const puppy& p)
{

    std::cout << "aww! the cute little puppy called " << p.name << " is barking: " << p.cute_noise() << std::endl;
}

struct wild_dog
{

    static const char* dog_type() { return "wild dog"; }
};

void do_howl(const wild_dog& d)
{
    std::cout << "the nameless wild dog called is howling" << std::endl;
}

struct doggy {

    struct concept {

        virtual void be_cute() const = 0;
        virtual void howl() const = 0;

    };

    template<class T>
    struct model : concept
    {
        model(T&& t) : _t(std::move(t)) {}
        model(const T& t) : _t(t) {}

        void be_cute() const override
        {
            do_be_cute(_t);
        }

        void howl() const override
        {
            do_howl(_t);
        }

        T _t;
    };

    void howl() const {
        _impl->howl();
    }

    void be_cute() const {
        _impl->be_cute();
    }

    template<class T, std::enable_if_t<!std::is_base_of<doggy, T>::value>* = nullptr>
    doggy(T&& t) : _impl(std::make_shared<model<T>>(std::forward<T>(t)))
    {}


    std::shared_ptr<concept> _impl;
};

int main()
{
    std::vector<doggy> dogs = {
        doggy(dog("rover")),
        doggy(puppy("poochums")),
        doggy(wild_dog())
    };

    for (const auto& d : dogs)
    {
        d.howl();
        d.be_cute();
    }

    return 0;
}

在这种特殊情况下,
doggie
具有共享的实现语义。如果希望创建不同的副本,请将
共享的\u ptr
替换为
唯一的\u ptr
,提供副本构造函数,并向
概念中添加
克隆()
方法(在
模型中有相应的实现)空隙设置狗(C++狗和狗)。克里托斯;这很奇怪,因为在我的Eclipse IDE中,它会告诉我“Dog”没有“drinkMilk”方法,因此不会编译。@Xari举例说,PuppyDog有一个其他Dog没有的drinkMilk()函数,但我仍然希望能够访问它。-然后,如果你调用的函数是“一般”< C++ >代码>函数,你就有一个设计缺陷。它是奇怪的,因为在我的Eclipse IDE中,它会告诉我“狗”没有方法“喝牛奶”,因此不会编译“-我不知道为什么你会感到惊讶,因为狗没有一个方法。您可以返回指向实例的指针或引用。如果不进行切片,则无法返回副本,因为编译器无法根据子类的超类来告诉子类的实例要保留多少内存。你是在用java或C++来讨论吗?在爪哇,没有任何切片,因为所有对象都是通过引用处理的。在C++中,如果不想切片,你应该通过引用:<代码>空隙设置狗(C++狗和狗)。克里托斯;这很奇怪,因为在我的Eclipse IDE中,它会告诉我“Dog”没有“drinkMilk”方法,因此不会编译。@Xari举例说,PuppyDog有一个其他Dog没有的drinkMilk()函数,但我仍然希望能够访问它。-如果您调用的函数是“general”
Dog
函数,那么您就有了一个设计缺陷。@Xari“这很奇怪,因为在我的Eclipse IDE中,它会告诉我“Dog”没有“drinkMilk”方法,因此不会编译”-我不知道为什么这会让您感到惊讶,因为狗没有喝牛奶的方法。如果我只想让一只小狗喝牛奶呢?我知道在您的例子中,您在Dog类中定义了它,然后在PuppyDog中重写了它,但是如果我只想在PuppyDog中使用它呢。通过引用传递可以解决这个问题吗?您需要
dynamic\u cast
。我将添加一个示例
#include <iostream>
#include <typeinfo>
#include <memory>
#include <string>
#include <utility>
#include <type_traits>
#include <vector>

// default cases
template<class T>
void do_howl(const T&)
{
    std::cout << "a " << T::dog_type() << " cannot howl" << std::endl;
}

template<class T>
void do_be_cute(const T&)
{
    std::cout << "a " << T::dog_type() << " is not cute" << std::endl;
}


// now provide specialisations
struct dog
{
    dog(std::string s) : name(std::move(s)) {}
    std::string name;
    static const char* dog_type() { return "normal dog"; }
};

void do_howl(const dog& d)
{
    std::cout << "the dog called " << d.name << " is howling" << std::endl;
}


struct puppy
{
    puppy(std::string s) : name(std::move(s)) {}
    std::string name;
    std::string cute_noise() const { return "yip yip!"; }
    static const char* dog_type() { return "puppy"; }
};

void do_be_cute(const puppy& p)
{

    std::cout << "aww! the cute little puppy called " << p.name << " is barking: " << p.cute_noise() << std::endl;
}

struct wild_dog
{

    static const char* dog_type() { return "wild dog"; }
};

void do_howl(const wild_dog& d)
{
    std::cout << "the nameless wild dog called is howling" << std::endl;
}

struct doggy {

    struct concept {

        virtual void be_cute() const = 0;
        virtual void howl() const = 0;

    };

    template<class T>
    struct model : concept
    {
        model(T&& t) : _t(std::move(t)) {}
        model(const T& t) : _t(t) {}

        void be_cute() const override
        {
            do_be_cute(_t);
        }

        void howl() const override
        {
            do_howl(_t);
        }

        T _t;
    };

    void howl() const {
        _impl->howl();
    }

    void be_cute() const {
        _impl->be_cute();
    }

    template<class T, std::enable_if_t<!std::is_base_of<doggy, T>::value>* = nullptr>
    doggy(T&& t) : _impl(std::make_shared<model<T>>(std::forward<T>(t)))
    {}


    std::shared_ptr<concept> _impl;
};

int main()
{
    std::vector<doggy> dogs = {
        doggy(dog("rover")),
        doggy(puppy("poochums")),
        doggy(wild_dog())
    };

    for (const auto& d : dogs)
    {
        d.howl();
        d.be_cute();
    }

    return 0;
}
the dog called rover is howling
a normal dog is not cute
a puppy cannot howl
aww! the cute little puppy called poochums is barking: yip yip!
the nameless wild dog called is howling
a wild dog is not cute