Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.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
关于C+中接口类的用法+; 我在C++中使用接口类有一个问题,但是不知道它的名称以及如何搜索它。希望你能帮助我_C++_Interface_Polymorphism_Abstract Class - Fatal编程技术网

关于C+中接口类的用法+; 我在C++中使用接口类有一个问题,但是不知道它的名称以及如何搜索它。希望你能帮助我

关于C+中接口类的用法+; 我在C++中使用接口类有一个问题,但是不知道它的名称以及如何搜索它。希望你能帮助我,c++,interface,polymorphism,abstract-class,C++,Interface,Polymorphism,Abstract Class,我只想用一个简单的例子来说明我的问题 我有5种可能的物体,像三角形、正方形、矩形、五边形和六边形 所有这些对象都有公共属性,因此我将有一个接口类形状 现在,我想要的是:我将拥有一个Shape类对象,并且由于运行时的选择,我希望能够将其用作其他5个对象之一 所以我做了如下的事情: class Shape { public: virtual int getArea()=0; virtual void setWidth(int w) { width = w

我只想用一个简单的例子来说明我的问题

我有5种可能的物体,像三角形、正方形、矩形、五边形和六边形

所有这些对象都有公共属性,因此我将有一个接口类形状

现在,我想要的是:我将拥有一个Shape类对象,并且由于运行时的选择,我希望能够将其用作其他5个对象之一

所以我做了如下的事情:

class Shape 
{
public:

    virtual int getArea()=0;

    virtual void setWidth(int w)
    {
        width = w;
    }

    virtual void setHeight(int h)
    {
        height = h;
    }


protected:
    int width;
    int height;
};



class Triangle: public Shape
{
public:

    int getArea()
    { 
        return (m_Width * m_Height)/2; 
    }

};

class Rectangle: public Shape
{
public:

    int getArea()
    { 
        return (m_Width * m_Height); 
    }

};
使用时,我只想创建一个Shape对象,并用一个派生类初始化它。因此,从那时起,我希望它的行为像该对象的一个实例,如下所示:

void main(){

 Shape* shape;

 std::string shapeType;

 std::cout<<"Enter Shape Type: triangle or rectangle."<<std::endl;

 std::cin>>shapeType;


 if (shapeType == "triangle")
     shape = new Triangle();
 else if (shapeType == "rectangle")
     shape = new Rectangle();


 shape->setWidth(5);
 shape->setHeight(7);

 std::cout<<shape->getArea()<<std::endl;


}
但这并不是一个好的处理方法,你可能会这么认为。除此之外,我只知道一种方法,强制我将所有这些属性写入Shape类,并在所需的派生类中实现它们,如果不需要其他类,则将其实现为空

你有解决这个问题的好办法吗?我相信会有,但我对这个问题没有太多经验,所以希望你有一个适合我需要的解决方案


提前谢谢

这绝对不是你解释的方式。这不是传统的意义。你应该读一读关于赫拉迪廷的书。基本上它的规则是:如果你创建了一个下属,你可以使用父级的函数和属性,如果它们是公共的或受保护的

如果你的类型是一个
形状
,这意味着你打算将它用作
形状
。如果要使用某个特定的子类,请使用该特定类型

如果您仍然希望存储泛型类型,并且仍然希望使用某些特定的操作,那么您需要使用
静态类型转换
,将指针向下转换到子类指针,但是您需要知道存储在那里的是哪种类型,或者使用
动态类型转换
,在这两种情况下,这看起来都是糟糕的设计


您应该能够使用虚拟函数执行所有多态操作,或者根据情况和您的需要,您可以使用其他设计模式,如。

如果属性仅与派生的相关,而与基无关,那么在基中实现它是没有意义的。例如,属性
isEquilateral()
应该在三角形类中实现,而不是在形状基类中实现

因此,您可以使用一个
Type()
属性,该属性在给出派生对象类型(三角形、矩形等)的每个派生类中重新实现

然后是静态铸造:

Triangle *triangle = static_cast<Triangle*>(shape);
Triangle*Triangle=static\u cast(形状);
比如说:

if (shape->Type() == Shape::Triangle){
    Triangle *triangle = static_cast<Triangle*>(shape);
    bool eq = triangle->isEquilateral();
    ...
}
if(shape->Type()==shape::Triangle){
三角形*三角形=静态铸件(形状);
bool eq=三角形->等边();
...
}
或者简单地说:

 Triangle *triangle = static_cast<Triangle*>(shape);
 if (triangle){
     bool eq = triangle->isEquilateral();
     ...
 }
Triangle*Triangle=static\u cast(形状);
if(三角形){
bool eq=三角形->等边();
...
}

但是我更喜欢第一种方法。

我认为需要使用指向基类的指针来存储对象。因此,您有
Shape*
,用于存储
新三角形()
,并且您应该能够访问必需的函数和变量。这是基于记住如何在向量中进行,这更详细,但我不明白为什么它不会转移

Shape* shape;
shape = new Triangle();
//shape->foo accesses Triangle methods

要么是这样,要么在运行时使用动态/静态转换将其转换为正确的类型,尽管这意味着您需要检查它是什么类型,以便执行正确的转换(因此可能有一个标识字符串或每个子类设置的基类中的某个内容)

首先,您的
Shape
不是接口,但是基本实现类。把它们分开

接口是一个抽象类,只有纯虚方法和虚析构函数:

struct IShape
{
    virtual int getArea() =0;
    virtual void setWidth(int w) =0;
    virtual void setHeight(int h) =0;
    // without virtual destructor you cannot
    // properly destroy object through IShape pointer
    virtual ~IShape() {}
};
现在让我们编写基本实现:

class CShapeBaseImpl : public IShape
{
public:
    void setWidth(int w) override { width_ = w; }
    void setHeight(int h) override { height_ = h; }
protected:
    int width_ = 0;
    int height_ = 0;
};
在大多数情况下,您希望创建一些具体的对象,并仅通过其接口使用它。通常通过以下方式完成:

std::unique_ptr CreateTriangle(inta、intb、intc)
{
自动三角形=标准::使_唯一(a、b、c);
//在那里你可以把它当作三角形
返回三角形;
}
CreateTriangle
返回后,最好忘记它是
Triangle
。现在才是IShape。

所有动物都会吠叫吗

考虑这样的层次结构

-> animal
   -> dog 
      -> great_dane       
      -> chiwawa
   -> fish
      -> tuna
      -> shark
有些人认为,如果你有一组
animal*
-s,你想让它们吠叫,
animal
必须声明一个抽象的
virtual void bark()=0
,以便在
great_dane
chiwa
(第一个是
cout as_a());
如果(mydog)mydog->树皮();

现在,把动物变成形状,把狗变成长方形,把鱼变成三角形!

这个问题没有好的解决办法。你可以用基本上无用的虚拟函数来填充你的基类,或者使用动态施法、标记的联合体、访问者模式……所有这些都不好。选择你的毒药。别忘了虚拟析构函数。为什么不返回一个uniq呢ue_ptr?如果调用者想要放弃它的安全性,应该由调用者决定。@Neil,你是对的。我经常使用dll和COM风格的接口。这是我的习惯。=)你可能需要一个
std::move
在那里,而不是在那里sure@Neil,
std::move
在那里是不必要的:
std::unique_ptr<IShape> CreateTriangle( int a, int b, int c )
{
    auto triangle = std::make_unique<Triangle>(a,b,c);
    // there you can work with it as Triangle
    return triangle;
}
-> animal
   -> dog 
      -> great_dane       
      -> chiwawa
   -> fish
      -> tuna
      -> shark
template<class T>
T* animal::as_a() { return dynamic_cast<T*>(this); }
auto mydog = myanimal->as_a<dog>();
if(mydog) mydog->bark();