首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++的多态性

C++的多态性
EN

Stack Overflow用户
提问于 2011-05-02 07:35:10
回答 6查看 57.2K关注 0票数 134

AFAIK:

C++提供了三种不同类型的多态性。

  • 虚函数
  • 函数名重载
  • 操作者超载

除了上述三种类型的多态性之外,还有其他类型的多态性:

  • 运行时间
  • 编译时
  • ad多态性
  • 参数多态性

我知道运行时多态可以通过虚拟函数来实现,静态多态性可以通过模板函数来实现。

但另外两个人

  • ad多态性
  • 参数多态网站上说

ad多态性:

如果可以使用的实际类型的范围是有限的,并且必须在使用之前单独指定组合,则这称为ad多态性。

参数多态性:

如果所有代码都是在没有提到任何特定类型的情况下编写的,并且因此可以与任意数量的新类型一起透明地使用,则称为参数多态。

我几乎听不懂。

如果可能的话,有人能用一个例子来解释这两个问题吗?我希望这些问题的答案将有助于许多新的学生通过考试。

EN

回答 6

Stack Overflow用户

发布于 2013-11-17 08:15:41

在C++中,重要的区别是运行时与编译时绑定。正如我稍后将解释的那样,即席与参数化并没有真正的帮助。

代码语言:javascript
运行
复制
|----------------------+--------------|
| Form                 | Resolved at  |
|----------------------+--------------|
| function overloading | compile-time |
| operator overloading | compile-time |
| templates            | compile-time |
| virtual methods      | run-time     |
|----------------------+--------------|

注释运行时多态仍然可以在编译时解析,但这只是优化。需要高效地支持运行时解决方案,并与其他问题进行权衡,是导致虚拟函数成为其本质的部分原因。对于C++中的所有形式的多态性来说,这都是关键--每种多态性都来自于在不同的环境中进行的不同的权衡。

函数重载和操作符重载在所有重要方面都是相同的。使用它们的名称和语法不影响多态性。

模板允许您一次指定许多函数重载。

同样的分辨率-时间概念还有另外一组名字.

代码语言:javascript
运行
复制
|---------------+--------------|
| early binding | compile-time |
| late binding  | run-time     |
|---------------+--------------|

这些名称更多地与OOP相关联,因此说模板或其他非会员函数使用早期绑定有点奇怪。

为了更好地理解虚拟函数和函数重载之间的关系,理解“单调度”和“多调度”的区别也是非常有用的。这个想法可以理解为一个进步..。

  • 首先,存在单纯函数。函数的实现是由函数名唯一标识的。没有一个参数是特殊的。
  • 然后,有一个单一的调度。其中一个参数被认为是特殊的,并使用(以及名称)来标识要使用的实现。在OOP中,我们倾向于将这个参数看作“对象”,在函数名称之前列出它。
  • 然后,有多个调度。任何/所有参数都有助于确定要使用的实现。因此,再一次,没有任何参数需要是特殊的。

显然,OOP不仅仅是将一个参数指定为特殊参数的借口,但这是其中的一部分。回到我所说的权衡--单一调度非常容易高效地完成(通常的实现称为“虚拟表”)。多分派不仅在效率方面更尴尬,而且对于单独编译也是如此。如果你好奇的话,你可能会查到“表达问题”。

正如对非成员函数使用“早期绑定”一词有点奇怪一样,在编译时使用“单次分派”和“多重分派”这两个术语也有点奇怪。通常,C++被认为没有多个调度,这被认为是一种特殊的运行时解决方案。然而,函数重载可以看作是在编译时完成的多个分派。

回到参数和即席多态之间,这些术语在函数式编程中更流行,在C++中不太适用。即便如此..。

参数多态意味着您将类型作为参数,并且无论您对这些参数使用何种类型,都使用完全相同的代码。

ad多态性是指根据特定类型提供不同的代码。

重载和虚拟函数都是即席多态的例子。

又有几个同义词..。

代码语言:javascript
运行
复制
|------------+---------------|
| parametric | unconstrained |
| ad-hoc     | constrained   |
|------------+---------------|

不过,这些不是完全同义词,尽管它们通常被当作是同义词,这也是C++中可能出现混淆的地方。

将这些作为同义词处理的理由是,通过将多态性限制到特定类型类,就可以使用特定于这些类型类的操作。此处的"classes“一词可以从OOP的意义上解释,但实际上只是指(通常是命名的)一组共享某些操作的类型。

因此,参数多态性通常被认为(至少在默认情况下)意味着不受约束的多态性。因为不管类型参数如何,都使用相同的代码,所以唯一可支持的操作是那些对所有类型都有效的操作。通过不受约束地设置类型集,可以严格限制可应用于这些类型的操作集。

例如,Haskell,你可以.

代码语言:javascript
运行
复制
myfunc1 :: Bool -> a -> a -> a
myfunc1 c x y = if c then x else y

这里的a是一种无约束的多态类型。它可能是任何东西,所以我们对这种类型的值无能为力。

代码语言:javascript
运行
复制
myfunc2 :: Num a => a -> a
myfunc2 x = x + 3

在这里,a被限制为Num类的成员--它们的作用类似于数字。该约束允许您使用这些值执行数字操作,例如添加它们。即使是3也是多态类型推断,表明您指的是a类型的3

我认为这是受约束的参数多态性。只有一个实现,但只能在受约束的情况下应用。ad方面是+3使用的选择。Num的每个“实例”都有自己独特的实现。所以,即使在Haskell中,“参数化”和“无约束”也不是真正的同义词--别怪我,这不是我的错!

在C++中,重载和虚拟函数都是即席多态.ad多态性的定义并不关心实现是在运行时选择还是在编译时选择。

如果每个模板参数都具有typename类型,则typename非常接近于模板的参数多态性。有类型参数,不管使用哪种类型,都有一个实现。然而,“替换失败不是错误”规则意味着由于在模板中使用操作而产生隐式约束。其他复杂因素包括模板专门化以提供替代模板--不同的(特别的)实现。

因此,在某种程度上,C++具有参数多态,但它是隐式约束的,并且可能被特殊的替代品所覆盖--也就是说,这种分类对于C++并不有效。

票数 15
EN

Stack Overflow用户

发布于 2011-05-02 07:44:35

至于ad多态性,它意味着函数重载或操作符重载.请看这里:

多态

至于参数多态,模板函数也可以计算在内,因为它们不一定接受固定类型的参数。例如,一个函数可以对整数数组进行排序,也可以对字符串数组进行排序,等等。

多态

票数 2
EN

Stack Overflow用户

发布于 2013-12-27 18:45:40

这可能没有任何帮助,但我这样做是为了向我的朋友介绍编程,我给出了定义的函数,比如START,以及主函数的END,这样就不会太让人望而生畏(他们只使用main.cpp文件)。它包含多态类和结构、模板、向量、数组、预处理器指令、友谊、运算符和指针(在尝试多态之前,您可能应该知道所有这些):

备注:它还没有完成,但是您可以得到的想法

main.cpp

代码语言:javascript
运行
复制
#include "main.h"
#define ON_ERROR_CLEAR_SCREEN false
START
    Library MyLibrary;
    Book MyBook("My Book", "Me");
    MyBook.Summarize();
    MyBook += "Hello World";
    MyBook += "HI";
    MyBook.EditAuthor("Joe");
    MyBook.EditName("Hello Book");
    MyBook.Summarize();
    FixedBookCollection<FairyTale> FBooks("Fairytale Books");
    FairyTale MyTale("Tale", "Joe");
    FBooks += MyTale;
    BookCollection E("E");
    MyLibrary += E;
    MyLibrary += FBooks;
    MyLibrary.Summarize();
    MyLibrary -= FBooks;
    MyLibrary.Summarize();
    FixedSizeBookCollection<5> Collection("My Fixed Size Collection");
    /* Extension Work */ Book* Duplicate = MyLibrary.DuplicateBook(&MyBook);
    /* Extension Work */ Duplicate->Summarize();
END

main.h

代码语言:javascript
运行
复制
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <type_traits>
#include <array>
#ifndef __cplusplus
#error Not C++
#endif
#define START int main(void)try{
#define END GET_ENTER_EXIT return(0);}catch(const std::exception& e){if(ON_ERROR_CLEAR_SCREEN){system("cls");}std::cerr << "Error: " << e.what() << std::endl; GET_ENTER_EXIT return (1);}
#define GET_ENTER_EXIT std::cout << "Press enter to exit" << std::endl; getchar();
class Book;
class Library;
typedef std::vector<const Book*> Books;
bool sContains(const std::string s, const char c){
    return (s.find(c) != std::string::npos);
}
bool approve(std::string s){
    return (!sContains(s, '#') && !sContains(s, '%') && !sContains(s, '~'));
}
template <class C> bool isBook(){
    return (typeid(C) == typeid(Book) || std::is_base_of<Book, C>());
}
template<class ClassToDuplicate> class DuplicatableClass{ 
public:
    ClassToDuplicate* Duplicate(ClassToDuplicate ToDuplicate){
        return new ClassToDuplicate(ToDuplicate);
    }
};
class Book : private DuplicatableClass<Book>{
friend class Library;
friend struct BookCollection;
public:
    Book(const char* Name, const char* Author) : name_(Name), author_(Author){}
    void operator+=(const char* Page){
        pages_.push_back(Page);
    }
    void EditAuthor(const char* AuthorName){
        if(approve(AuthorName)){
            author_ = AuthorName;
        }
        else{
            std::ostringstream errorMessage;
            errorMessage << "The author of the book " << name_ << " could not be changed as it was not approved";
            throw std::exception(errorMessage.str().c_str());
        }
    }
    void EditName(const char* Name){
        if(approve(Name)){
            name_ = Name;
        }
        else{
            std::ostringstream errorMessage;
            errorMessage << "The name of the book " << name_ << " could not be changed as it was not approved";
            throw std::exception(errorMessage.str().c_str());
        }
    }
    virtual void Summarize(){
        std::cout << "Book called " << name_ << "; written by " << author_ << ". Contains "
            << pages_.size() << ((pages_.size() == 1) ? " page:" : ((pages_.size() > 0) ? " pages:" : " pages")) << std::endl;
        if(pages_.size() > 0){
            ListPages(std::cout);
        }
    }
private:
    std::vector<const char*> pages_;
    const char* name_;
    const char* author_;
    void ListPages(std::ostream& output){
        for(int i = 0; i < pages_.size(); ++i){
            output << pages_[i] << std::endl;
        }
    }
};
class FairyTale : public Book{
public:
    FairyTale(const char* Name, const char* Author) : Book(Name, Author){}
};
struct BookCollection{
friend class Library;
    BookCollection(const char* Name) : name_(Name){}
    virtual void operator+=(const Book& Book)try{
        Collection.push_back(&Book); 
    }catch(const std::exception& e){
        std::ostringstream errorMessage;
        errorMessage << e.what() << " - on line (approx.) " << (__LINE__ -3);
        throw std::exception(errorMessage.str().c_str());
    }
    virtual void operator-=(const Book& Book){
        for(int i = 0; i < Collection.size(); ++i){
            if(Collection[i] == &Book){
                Collection.erase(Collection.begin() + i);
                return;
            }
        }
        std::ostringstream errorMessage;
        errorMessage << "The Book " << Book.name_ << " was not found, and therefore cannot be erased";
        throw std::exception(errorMessage.str().c_str());
    }
private:
    const char* name_;
    Books Collection;
};
template<class FixedType> struct FixedBookCollection : public BookCollection{
    FixedBookCollection(const char* Name) : BookCollection(Name){
        if(!isBook<FixedType>()){
            std::ostringstream errorMessage;
            errorMessage << "The type " << typeid(FixedType).name() << " cannot be initialized as a FixedBookCollection";
            throw std::exception(errorMessage.str().c_str());
            delete this;
        }
    }
    void operator+=(const FixedType& Book)try{
        Collection.push_back(&Book); 
    }catch(const std::exception& e){
        std::ostringstream errorMessage;
        errorMessage << e.what() << " - on line (approx.) " << (__LINE__ -3);
        throw std::exception(errorMessage.str().c_str());
    }
    void operator-=(const FixedType& Book){
        for(int i = 0; i < Collection.size(); ++i){
            if(Collection[i] == &Book){
                Collection.erase(Collection.begin() + i);
                return;
            }
        }
        std::ostringstream errorMessage;
        errorMessage << "The Book " << Book.name_ << " was not found, and therefore cannot be erased";
        throw std::exception(errorMessage.str().c_str());
    }
private:
    std::vector<const FixedType*> Collection;
};
template<size_t Size> struct FixedSizeBookCollection : private std::array<const Book*, Size>{
    FixedSizeBookCollection(const char* Name) : name_(Name){ if(Size < 1){ throw std::exception("A fixed size book collection cannot be smaller than 1"); currentPos = 0; } }
    void operator+=(const Book& Book)try{
        if(currentPos + 1 > Size){
            std::ostringstream errorMessage;
            errorMessage << "The FixedSizeBookCollection " << name_ << "'s size capacity has been overfilled";
            throw std::exception(errorMessage.str().c_str());
        }
        this->at(currentPos++) = &Book;
    }catch(const std::exception& e){
        std::ostringstream errorMessage;
        errorMessage << e.what() << " - on line (approx.) " << (__LINE__ -3);
        throw std::exception(errorMessage.str().c_str());
    }
private:
    const char* name_;
    int currentPos;
};
class Library : private std::vector<const BookCollection*>{
public:
    void operator+=(const BookCollection& Collection){
        for(int i = 0; i < size(); ++i){
            if((*this)[i] == &Collection){
                std::ostringstream errorMessage;
                errorMessage << "The BookCollection " << Collection.name_ << " was already in the library, and therefore cannot be added";
                throw std::exception(errorMessage.str().c_str());
            }
        }
        push_back(&Collection);
    }
    void operator-=(const BookCollection& Collection){
        for(int i = 0; i < size(); ++i){
            if((*this)[i] == &Collection){
                erase(begin() + i);
                return;
            }
        }
        std::ostringstream errorMessage;
        errorMessage << "The BookCollection " << Collection.name_ << " was not found, and therefore cannot be erased";
        throw std::exception(errorMessage.str().c_str());
    }
    Book* DuplicateBook(Book* Book)const{
        return (Book->Duplicate(*Book));
    }
    void Summarize(){
        std::cout << "Library, containing " << size() << ((size() == 1) ? " book collection:" : ((size() > 0) ? " book collections:" : " book collections")) << std::endl;
        if(size() > 0){
            for(int i = 0; i < size(); ++i){
                std::cout << (*this)[i]->name_ << std::endl;
            }
        }
    }
};
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5854581

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档