【问题标题】:vtable error in Number and Shape super classesNumber 和 Shape 超类中的 vtable 错误
【发布时间】:2019-10-19 04:11:44
【问题描述】:

我在超类是 Number 和 Shape 的类开发人员中遇到困难。

实际上,我贴上了虚拟标签,这很容易导致例如 vtable 的错误,我仔细检查了 stackoverflow 中有关 vtable 的所有帖子以及 void 的错误使用,但我最终无法解决此类问题.

您能帮我考虑一下吗?我花了一个多星期来思考这个问题,这真的让我很反感......

如果我的问题需要更多补充的东西,请不要犹豫发表评论,我很乐意与之互动。

NumberMain 程序包括有 NumberMain 的 Complex、Fraction 和 Number。

ShapeMain 程序包括圆形、Shape、Square 和带有 ShapeMain 的三角形。

Circle.cpp

// This class describes the implementation of a Circle

#include <iostream>
#include "Shape.h"
#include "Circle.h"

using namespace std;

Circle & Circle::setCenterX(float newX) {
   centerX = newX;
   return (*this);
}

Circle & Circle::setCenterY(float newY) {
   centerY = newY;
   return (*this);
}

// This function changes the radius of the circle. Use validation to ensure radius >=0.

void Circle::setRadius(float newRadius) {
   if(newRadius >= 0) {
       radius = newRadius;
   }
   else {
       cout << "Error: radius should be at least 0." << endl;
   }
}

// This function returns the X coordinate of the center of the circle.

float Circle::getX() const {
   return centerX;
}

// This function returns the Y coordinate of the center of the circle.

float Circle::getY() const {
   return centerY;
}

// This function returns the radius of the circle.

float Circle::getRadius() const {
   return radius;
}

// This function returns the area of the circle.

float Circle::getArea() const {
   return radius * radius * PI;
}

// This function returns the diameter of the circle.

float Circle::getDiameter() const {
   return 2 * radius;
}

// This function returns the circumference of the circle.

float Circle::getCircumference() const {
   return 2 * PI * radius;
}

圆.h

// Circle.h
// This class describes the data and actions for a Circle
#include<iostream>

const float PI = 3.14159;

class Circle : public Shape {
   private:
       float centerX, centerY, radius;
   public:
       Circle & setCenterX(float newX);
       Circle & setCenterY(float newY);
       void setRadius(float newRadius);
       float getX() const;
       float getY() const;
       float getRadius() const;
       float getArea() const;
       float getDiameter() const;
       float getCircumference() const;
};

形状.cpp

// Shape.cpp
// This file describes the Shape class.

#include <iostream>
#include "Shape.h"

using namespace std;

void Shape::setColor(int newColor) {
   color = newColor;
}

void Shape::printColor() const {
   switch(color) {
       case RED : cout << "Red"; break;
       case BLUE : cout << "Blue"; break;
       case GREEN : cout << "Green"; break;
       default : cout << "Black";
   }
}

形状.h

// Shape.h
// This file describes the Shape class.

#include <iostream>

const int RED = 1;
const int BLUE = 2;
const int GREEN = 3;

class Shape {
    protected:
        int color;
    public:
        virtual void setColor(int newColor);
        void printColor() const;
        virtual float getArea() const = 0;
};

ShapeMain.cpp

#include <iostream>
#include <stdexcept>
#include "Shape.h"
#include "Circle.h"
#include "Square.h"
#include "Triangle.h"

using namespace std;

// Create and return a Square
Square * makeSquare() {
   Square * square1 = new Square();
   float sideLength;

   cout << "What is the Side Length?";
   cin >> sideLength;
   square1->setCenterX(0).setCenterY(0).setSideLength(sideLength);
   return square1;
}

// Create and return a Circle
Circle * makeCircle() {
   Circle * circle1 = new Circle;
   float radius;

   cout << "What is the Radius?";
   cin >> radius;
   circle1->setCenterX(0).setCenterY(0).setRadius(radius);
   return circle1;
}

Triangle * makeTriangle() {
   Triangle * triangle1 = new Triangle();
   float height, width;

   cout << "What is the Height?";
   cin >> height;
   cout << "What is the Width?";
   cin >> width;
   triangle1->setHeight(height).setWidth(width).setLeft(0).setBottom(0);
   return triangle1;
}

// Create and return a Color
int makeColor() {
   int color;

   cout << RED << ") Red or " << BLUE << ") Blue or " << GREEN << ") Green? ";
   cin >> color;
   return color;
}

int main() {
   Shape * shape1;
   int color;

   int shapeType;

   cout << "1) Square or 2) Circle or 3) Triangle?";
   cin >> shapeType;

   switch(shapeType) {
       case 1 : shape1 = makeSquare(); break;
       case 2 : shape1 = makeCircle(); break;
       case 3 : shape1 = makeTriangle(); break;
       default : throw runtime_error("Invalid Shape Class");
    }

   color = makeColor();
   shape1 -> setColor(color);

   // The getAre() function is polymorphic.
   cout << "The Area is " << shape1->getArea() << endl;
   cout << "The Color is ";
   shape1->printColor();
   cout << endl;

   return 0;
}

Square.cpp

// Square.cpp

#include <iostream>
#include "Shape.h"
#include "Square.h"

using namespace std;

Square & Square::setCenterX(float newX) {
    centerX = newX;
    return (*this);
}

Square & Square::setCenterY(float newY) {
    centerY = newY;
    return (*this);
}

void Square::setSideLength(float newSideLength) {
    if(newSideLength >= 0) {
        sideLength = newSideLength;
    }
    else {
        cout << "Error: Side length should be at least 0." << endl;
    }
}

float Square::getCenterX() {
    return centerX;
}

float Square::getCenterY() {
    return centerY;
}

float Square::getSideLength() {
    return sideLength;
}

float Square::getArea() {
    return sideLength * sideLength;
}

float Square::getTop() {
    return centerY + sideLength / 2;
}

float Square::getBottom() {
    return centerY - sideLength / 2;
}

float Square::getLeft() {
    return centerX - sideLength / 2;
}

float Square::getRight() {
    return centerX + sideLength / 2;
}

方形.h

#include<iostream>

class Square : public Shape {
   private:
       float centerX, centerY, sideLength;
   public:
       Square & setCenterX(float newX);
       Square & setCenterY(float newY);
       void setSideLength(float newSideLength);
       float getCenterX();
       float getCenterY();
       float getSideLength();
       float getArea() const;
       float getTop();
       float getBottom();
       float getLeft();
       float getRight();
};

三角形.cpp

// Triangle.cpp

#include <iostream>
#include "Shape.h"
#include "Triangle.h"

using namespace std;

Triangle & Triangle::setHeight(float newHeight) {
   height = newHeight;
   return *this;
}

Triangle & Triangle::setWidth(float newWidth) {
   width = newWidth;
   return *this;
}

Triangle & Triangle::setBottom(float newBottom) {
   bottom = newBottom;
   return *this;
}

Triangle & Triangle::setLeft(float newLeft) {
   left = newLeft;
   return *this;
}

float Triangle::getHeight() const {
   return height;
}

float Triangle::getWidth() const {
   return width;
}

float Triangle::getBottom() const {
   return bottom;
}

float Triangle::getLeft() const {
   return left;
}

float Triangle::getArea() const {
   return ((height * width)/2);
}

void Triangle::setColor(int newColor) {
   if (newColor != RED) cout << "Triangles are always Red." << endl;
   color = RED;
}

三角形.h

#include<iostream>

class Triangle : public Shape {
   private:
       float height, width, bottom, left;
   public:
       Triangle & setHeight(float newHeight);
       Triangle & setWidth(float newWidth);
       Triangle & setBottom(float newBottom);
       Triangle & setLeft(float newLeft);
       float getHeight() const;
       float getWidth() const;
       float getBottom() const;
       float getLeft() const;
       float getArea() const;
       virtual void setColor(int newColor);
};

复杂的.cpp

// Complex.cpp
// This file describes the Complex class.

#include <iostream>
#include "Complex.h"

Complex::Complex() {
    real = 0;
    imag = 0;
}

Complex::Complex(float newReal) {
    real = newReal;
    imag = 0;
}

Complex::Complex(float newReal, float newImag) {
    real = newReal;
    imag = newImag;
}

void Complex::print() {
    cout << real << " + j(" << imag << ")" << endl << endl;
}

void Complex::setRealAndImaginary(float newReal, float newImag) {
    real = newReal;
    imag = newImag;
}

void Complex::setReal(float newReal) {
    real = newReal;
}

void Complex::setImaginary(float newImag) {
    imag = newImag
}

float Complex::getReal() {
    return real;
}

float Complex::getImaginary() {
    return imag;
}

// (a + bi) + (c + di) = (a + c) + (b + d)i
Complex Complex::operator+(Complex complex2) {
    Complex newComplex;
    float newReal = real + complex2.getReal();
    float newImag = imag + complex2.getImaginary();
    newComplex.setRealAndImaginary(newReal, newImag);

    return newComplex;
}

// (a + bi) - (c + di) = (a - b) + (b - d)i
Complex Complex::operator-(Complex complex2) {
    Complex newComplex;
    float newReal = real - complex2.getReal();
    float newImag = imag - complex2.getImaginary();
    newComplex.setRealAndImaginary(newReal, newImag);

    return newComplex;
}

// (a + bi) * (c + di) = (ac - bd) + (bc + ad)i
Complex Complex::operator*(Complex complex2) {
    Complex newComplex;
    float newReal = real*complex2.getReal() - imag*complex2.getImaginary();
    float newImag = imag*complex2.getReal() + real*complex2.getImaginary();
    newComplex.setRealAndImaginary(newReal, newImag);

    return newComplex;
}

// (a + bi) / (c + di) = (ac + bd) / (c^2 + d^2) + (bc - ad) / (c^2 + d^2)i
Complex Complex::operator/(Complex complex2) {
    Complex newComplex;
    float newReal = (real*complex2.getReal() + imag*complex2.getImaginary()) / (complex2.getReal()*complex2.getReal() + complex2.getImaginary()*complex2.getImaginary());
    float newImag = (imag*complex2.getReal() - real*complex2.getImaginary()) / (complex2.getReal()*complex2.getReal() + complex2.getImaginary()*complex2.getImaginary());
    newComplex.setRealAndImaginary(newReal, newImag);

    return newComplex;
}

bool Complex::operator==(Complex complex2) {
    return (real == complex2.getReal() && imag == complex2.getImaginary());
}

ostream & operator<<(ostream & output, Complex & complex1) {
    output << complex1.getReal() << " + j(" << complex1.getImaginary() << ")";
    return output;
}

复杂.h

// Complex.h
// This file describes the Complex class.

using namespace std;

class Complex : public Number {
    private:
        float real = 0;
        float imag = 0;
    public:
        Complex();
        Complex(float newReal);
        Complex(float newReal, float newImag);
        void print();
        void setRealAndImaginary(float newReal, float newImag);
        void setReal(float newReal);
        void setImag(float newImag);
        float getReal();
        float getImaginary();
        Complex operator+(Complex complex2);
        Complex operator-(Complex complex2);
        Complex operator*(Complex complex2);
        Complex operator/(Complex complex2);
        bool operator==(Complex complex2);
};

ostream & operator<<(ostream & output, Complex & complex1);

分数.cpp

// Fraction.cpp
// This file describes the Fraction class.

#include <iostream>
#include "Fraction.h"

// Constructors for Fraction.
// The default fraction is 0/1.
Fraction::Fraction() {
    setNumerAndDenom(0, 1);
}

// If only the numerator is given then the default denominator is 1.
Fraction::Fraction(int newNumer) {
    setNumerAndDenom(newNumer, 1);
}

Fraction::Fraction(int newNumer, int newDenom) {
    setNumerAndDenom(newNumer, newDenom);
}

//Print function for Fraction.
void Fraction::print() {
    cout << numerator << "/" << denominator;
}

// This function assigns the fraction to a new value.
void Fraction::setNumerAndDenom(int newNumer, int newDenom) {
    if (newDenom == 0) {
        cout << "Error creating a fraction with a zero denominator" << endl;
        return;
    }
    numerator = newNumer;
    denominator = newDenom;
    simplify();
}

// Return the numerator of the fraction.
int Fraction::getNumerator() {
    return numerator;
}

// Return the denominator of the fraction.
int Fraction::getDenominator() {
    return denominator;
}

// Simplify the fraction. For example 2/4 becomes 1/2.
void Fraction::simplify() {
    int gcd = GreatestCommonDenominator(numerator, denominator);

    numerator /= gcd;
    denominator /= gcd;
}

// Addition operator for Fraction
Fraction Fraction::operator+(Fraction frac2) {
    Fraction newFraction;
    int newDenom = denominator * frac2.getDenominator();
    int newNumer = numerator * frac2.getDenominator() + frac2.getNumerator() * denominator;
    newFraction.setNumerAndDenom(newNumer, newDenom);

    return newFraction;
}

// Subtraction operator for Fraction
Fraction Fraction::operator-(Fraction frac2) {
    Fraction newFraction;
    int newDenom = denominator * frac2.getDenominator();
    int newNumer = numerator * frac2.getDenominator() - frac2.getNumerator() * denominator;
    newFraction.setNumerAndDenom(newNumer, newDenom);

    return newFraction;
}

// Multiplication operator for Fraction
Fraction Fraction::operator*(Fraction frac2) {
    Fraction newFraction;
    int newDenom = denominator * frac2.getDenominator();
    int newNumer = numerator * frac2.getNumerator();
    newFraction.setNumerAndDenom(newNumer, newDenom);

    return newFraction;
}

// Division operator for Fraction
Fraction Fraction::operator/(Fraction frac2) {
    Fraction newFraction;
    int newDenom = denominator * frac2.getNumerator();
    int newNumer = numerator * frac2.getDenominator();
    newFraction.setNumerAndDenom(newNumer, newDenom);

    return newFraction;
}

// Equality comparison operator for Fraction
bool Fraction::operator==(Fraction frac2) {
    return (numerator * frac2.getDenominator() == denominator * frac2.getNumerator());
}

// Greater Than comparison operator for Fraction
bool Fraction::operator>(Fraction frac2) {
    return (numerator * frac2.getDenominator() > denominator * frac2.getNumerator());
}

// Less Than comparison operator for fraction
bool Fraction::operator<(Fraction frac2) {
    return (numerator * frac2.getDenominator() < denominator * frac2.getNumerator());
}

// Output operator for Fraction
ostream & operator<<(ostream & output, Fraction & frac) {
    output << frac.getNumerator() << "/" << frac.getDenominator();
    return output;
}

// This function returns the Greatest Common Denominator (GCD) of num1 and num2
int GreatestCommonDenominator(int num1, int num2) {
    if (num1 == 0) return num2;
    if (num1 < 0) return GreatestCommonDenominator(-num1, num2);
    if (num1 > num2) return GreatestCommonDenominator(num2, num1);
    return GreatestCommonDenominator(num2-num1, num1);
}

分数.h

// Fraction.h
// This file describes the Fraction class.

using namespace std;

class Fraction : public Number {
    private:
        int numerator, denominator;
    public:
        Fraction(); // Default fraction is 0/1.
        Fraction(int newNumer);
        Fraction(int newNumer, int newDenom);
        void print();
        void setNumerAndDenom(int newNumer, int newDenom);
        int getNumerator();
        int getDenominator();
        void simplify();
        Fraction operator+(Fraction frac2);
        Fraction operator-(Fraction frac2);
        Fraction operator*(Fraction frac2);
        Fraction operator/(Fraction frac2);
        bool operator==(Fraction frac2);
        bool operator>(Fraction frac2);
        bool operator<(Fraction frac2);
};

ostream & operator<<(ostream & output, Fraction & frac1);
int GreatestCommonDenominator(int num1, int num2);

数字.h

// Number.h
// This file describes the Number class.

class Number {
    public:
        void print() const;
};

NumberMain.cpp

// NumberMain.cpp
// This is the main file which demonstrates the Number class.

#include <iostream>
#include "Number.h"
#inlcude "Fraction.h"
#include "Complex.h"

using namespace std;

// Create and return a Complex
Complex * makeComplex() {
    Complex * complex1 = new Complex;
    float real, imag;

    cout << "What is the Real Part? ";
    cin >> real;
    cout << "What is the Imaginary Part? ";
    cin >> imag;
    complex1->setReal(real).setImaginary(imag);
    return complex1;
}

// Create and return a Fraction
Fraction * makeFraction() {
    Fraction * frac1 = new Fraction;
    int numer, denom;

    cout << "What is the Numerator? ";
    cin >> numer;
    cout << "What is the Denominator? ";
    cin >> denom;
    frac1->setNumerator(numer).setDenominator(denom).simplify();
    return frac1;
}

int main() {
    Number * num1;
    int numberType;

    cout << "1) Complex or 2) Fraction ";
    cin >> numberType;

    switch(numberType) {
        case 1 : num1 = makeComplex(); break;
        case 2 : num1 = makeFraction(); break;
        default : cout << "Error: Invalid Number Class" << endl; return 1;
    }

    // The print() function is polymorphic
    num1->print();
    cout << endl;

    return 0;
}

谢谢你。

【问题讨论】:

  • 除了我的回答中的其他要点之外,include 的拼写不正确,即#inlcude "Fraction.h"。还要注意这些错误。
  • 如果您的解决方案正常工作,请考虑通过Code Review 询问。如果您走这条路,请通读链接页面,以便调整您的问题以符合他们的规则。
  • 如果您希望您的问题得到更多关注,您可能需要查看How to Ask。我到了你问题的文本部分的结尾,却没有发现你的问题是什么,只是你有问题。 (更准确地说,您的 SO 问题的存在告诉我您遇到了问题;您的问题文本只是证实了这一点。)您的第一段既不吸引人,也不提供信息。提早放弃阅读并将这个问题留给“其他人”很容易。

标签: c++


【解决方案1】:

以下是您需要注意的代码中的一些要点:

  • 任何头文件中都没有标头保护,即循环包含同一文件会导致重新定义错误。
  • 头文件和源文件中的方法名不一样。
  • 方法链接与返回void 类型的方法一起使用。
  • 在某些情况下,函数在头文件中声明,但未在源文件中定义。

头文件

在头文件中使用以下格式:

// Use pragma directive where compilers support this
#pragma once

// ... code ...

否则,请像这样使用标头保护:

#ifndef MY_HEADER
#define MY_HEADER

// ... code ...

#endif

方法名称

确保头文件和源文件中的方法名称相同。

// Test.hpp
class Test
{
public:
    void print() const;
};

// Test.cpp
void Test::print() const
{
    // ...
}

方法链

这些方法是这样链接的:

complex1->setReal(real).setImaginary(imag);

但是,setReal() 和 setImaginary() 方法不返回任何内容,即 void。 [注意:标头中不存在 setImaginary()。它是setImag(),但在源文件中定义为setImaginary()。]

对于链接,方法应该返回当前对象的引用。在 SO 上有许多 Q&A 解决了这个问题!

但是,在您当前的代码中,您需要这样做:

complex1->setReal(real);
complex1->setImaginary(imag);

以上几点只是您的代码中存在的一些问题。可能还有更多。您需要遵循编译器报告的错误并解决这些问题。

以后,请创建MCVE 以减少您的代码,以便其他人可以轻松地自行跟踪和复制以提供足够的响应。

【讨论】:

  • 关于#pragma once 的注释可以被愚弄。这些天需要做一些工作,但符号链接和有趣的网络映射目录结构真的会搞砸。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 2022-01-16
  • 1970-01-01
  • 2013-02-22
  • 1970-01-01
  • 2021-10-16
相关资源
最近更新 更多