2014-02-26 48 views
3

很难使标题明确清晰,但我会尝试解释上下文(以及下面的一些代码)。注:我看过类似的问题,但他们只处理1个孩子的情况。所以他们对我的情况并没有真正的帮助,因为我有两个孩子班。C++在两个不同的子类中实现了虚拟方法的父类

上下文: 我有一个父类有2个孩子的形状:圆形和正方形。 我将有一个Shape对象的向量,但这些Shape对象实际上只能是Circle对象或Square对象。我需要Circle和Square类具有相同的父类,以便我可以将它们存储在同一个向量中。

诀窍是我需要使用矢量中的Shape对象来调用在Circle类或Square类中实现的方法,因此,我需要在父类中有一个“虚拟”版本的方法类形状。

下面是代码为我班的简化部分:

Shape.h:

class Shape{ 
public: 
    std::string getColor(); 

    virtual int getRadius() = 0; //Method implemented in Circle 
    virtual int getHeight() = 0; //Method implemented in Square 
    virtual int getWidth() = 0; //Method implemented in Square 

protected: 
    std::string color; 
}; 

class Circle : public Shape{ 
public: 
    int getRadius(); 

private: 
    int radius; 
}; 

class Square : public Shape{ 
public: 
    int getHeight(); 
    int getWidth(); 

private: 
    int height; 
    int width; 
}; 

在Shape.cpp我有这样的事情:

std::string Shape::getColor(){ 
    return color; 
} 

int Circle::getRadius(){ 
    return radius; 
} 

int Square::getHeight(){ 
    return height; 
} 

int Square::getWidth(){ 
    return width; 
} 

错误发生在main.cpp中,当我想创建圆形和方形对象时:

Circle *c = new Circle(...);//Error: cannot instantiate abstract class 
          //pure virtual function "Shape::getHeight" has no overrider 
          //pure virtual function "Shape::getWidth" has no overrider 


Square *s = new Square(...);//Error: cannot instantiate abstract class 
          //pure virtual function "Shape::getRadius" has no overrider 

所以好像我需要“getRadius”在Square类的声明和“的getHeight”和“的getWidth”在Circle类的声明...

我尝试添加他们与虚拟,但这使得圆形和方形抽象类,所以我不能与他们创建任何对象。

有没有办法让这项工作?

这是我发布在stackoverflow的第一个问题。我希望一切都很清楚。谢谢您的帮助!

+0

您必须至少为您在每个派生类中的Shape中声明的纯虚函数定义一个主体,或者这些类变为抽象基类并且不能实例化。 – larrylampco

+0

另外,你应该从'Shape'继承而不是'Shapes'。 – larrylampco

+0

Oups,我修好了。谢谢 – JLuc5

回答

1

您的虚拟方法不是真正为虚方法很好的候选人,因为他们有一个特定类的功能,但没有用其他的。

虚拟方法的好例子将由每个类实现,但具有不同的功能或结果,例如virtual int area()virtual bool intersects(Shape * otherShape)等等。

无论如何,你这是怎么会被编译(有一些额外的)代码:

形状:

class Shape{ 
public: 
    std::string getColor(); 

    Shape() {} 
    virtual ~Shape() {} 

    virtual int getRadius() { return 0; } // no pure virtual 
    virtual int getHeight() { return 0; } // no pure virtual 
    virtual int getWidth() { return 0; } // no pure virtual 

protected: 
    std::string color; 
}; 


class Circle : public Shape { 
public: 
    Circle(int r) 
     : Shape() 
     , radius(r) 
    {} 

    Circle() : Circle(0) {} 
    ~Circle() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 

    int getRadius() override { return radius; }; 

private: 
    int radius; 
}; 

方:

class Square : public Shape { 
public: 
    Square(int h, int w) 
     : Shape() 
     , height(h) 
     , width(w) 
    {} 

    Square() : Square(0, 0) {} 
    ~Square() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 

    int getHeight() override { return height; } 
    int getWidth() override { return width; } 

private: 
    int height; 
    int width; 
}; 

测试:

int main() { 
    using shapes = std::vector< Shape * >; 

    shapes s; 
    s.push_back(new Circle(10)); 
    s.push_back(new Square()); 
    s.push_back(new Square(1, 3)); 
    s.push_back(new Circle()); 

    for (Shape * sh : s) { 
     std::cout 
      << " r " << sh->getRadius() 
      << " h " << sh->getHeight() 
      << " w " << sh->getWidth() 
      << std::endl; 
    }  

    for (Shape * sh : s) { delete sh; } s.clear(); 
} 

输出:

r 10 h 0 w 0 
r 0 h 0 w 0 
r 0 h 1 w 3 
r 0 h 0 w 0 
virtual Circle::~Circle() 
virtual Square::~Square() 
virtual Square::~Square() 
virtual Circle::~Circle() 

这里是一个更好地利用带面积示例虚拟方法:

#include <iostream> 
#include <vector> 

struct Shape { 
    Shape() {} 
    virtual ~Shape() {} 

    virtual double area() = 0; 
}; 

具有不同区域的实施延伸:

struct Circle : public Shape { 
    Circle(int r) 
     : Shape() 
     , radius(r) 
    {} 

    Circle() : Circle(0) {} 
    ~Circle() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 

    virtual double area() override { return radius * radius * 3.14; } 

    int radius; 
}; 

struct Square : public Shape { 
    Square(int h, int w) 
     : Shape() 
     , height(h) 
     , width(w) 
    {} 

    Square() : Square(0, 0) {} 
    ~Square() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 

    virtual double area() override { return height * width; } 

    int height; 
    int width; 
}; 

测试

int main() { 
    using shapes = std::vector< Shape * >; 

    shapes s; 
    s.push_back(new Circle(1)); 
    s.push_back(new Square(1, 1)); 
    s.push_back(new Square(2, 3)); 
    s.push_back(new Circle(2)); 

    for (Shape * sh : s) { 
     std::cout << sh->area() << std::endl; 
    } 

    for (Shape * sh : s) { delete sh; } s.clear(); 
} 

输出:

3.14 
1 
6 
12.56 
virtual Circle::~Circle() 
virtual Square::~Square() 
virtual Square::~Square() 
virtual Circle::~Circle() 
+0

这听起来像一个有趣的方式来做到这一点。我明天会在代码中测试它。我有一个快速的问题给你。 “for(Shape * sh:s)”和迭代器一样:“for(vector :: iterator sh = objects.begin(); sh!= objects.end(); ++ sh) {(* sh) - > area()}。非常感谢! – JLuc5

+0

@ JLuc5是的,它与迭代器 – stefanB

+1

相同这将得到代码编译,但不会增加一个* sense *的iota。 –

0

我希望你知道pure virtualvirtual函数之间的区别。 Pure virtual函数实质上是占位符函数,与没有正文。你的基类的形状更适合普通的virtual函数,这些函数可以但不必在子类中进行更改。取出函数声明中的= 0部分以使函数仅为virtual函数。

+0

这就是我所做的之前,但之后,我不需要在我的Shape.cpp文件中给它们一个空的主体? 如果我这样做,那么当我从矢量中的Shape对象中调用方法时,是不是会使用空体定义的函数?而不是使用来自Circle或Square类的正确答案? 我可以添加一些代码来解释我想如何使用Shape对象的向量。 – JLuc5

0

这应该让你朝着正确的方向前进。通过让你的成员不是纯虚拟的,你可以在派生类中实现它们,但是你不需要。

class Shape{ 
    public: 
    std::string getColor(); 

    virtual int getRadius(); //Method implemented in Circle 
    virtual int getHeight(); //Method implemented in Square 
    virtual int getWidth(); //Method implemented in Square 

protected: 
    std::string color; 
}; 

class Circle : public Shape{ 
public: 
    int getRadius(); 

private: 
    int radius; 
}; 

class Square : public Shape{ 
public: 
    int getHeight(); 
    int getWidth(); 

private: 
    int height; 
    int width; 
}; 
+0

我试过这样做,但那么,这意味着我必须在“形状”中给这些虚拟方法一个正确的身体吗?我可以使它成为一个空的主体,但是随后每当我从向量中的Shape对象调用getRadius()时,它都将使用该空主体而不是Circle类中的一个,不是吗? 这可能很奇怪,但我需要能够使用向量中的Shape对象调用getRadius()(*该对象最初将被创建为Circle *),并使其执行Circle ::中定义的内容。 getRadius(){...} – JLuc5

+0

@ JLuc5如果通过形状对象表示“Shape myShape”,那么是的,它将调用空体。但是,Shape * myShape = new Circle()'不会。 – larrylampco

+0

Shape * myShape = new Circle(); ...我可能需要尝试一下。我不知道你可以这样做。谢谢 – JLuc5

相关问题