Виртуальное наследование, которое не показывает желаемый результат

#c

#c

Вопрос:

Я получил файл заголовка с именем Shape.h, и мне было поручено создать 4 других файла заголовков, каждый из которых представляет формы: квадрат, прямоугольник, круг и эллипс.

Форма файла заголовка наследуется четырьмя другими файлами заголовков, и исходный файл должен выдавать выходные данные соответственно файлам заголовков.

Я написал коды просто отлично, но результат не даст ожидаемого результата, мне нужна помощь здесь.

Я попросил своих инструкторов о помощи, даже если они помогли, это отняло много времени, но оно того стоило.

реальная проблема здесь в том, что я отлаживал, просматривал код и пробовал разные вещи в коде, но я либо получаю тот же нежелательный результат, либо сообщение об ошибке.

Это базовый файл:

 #pragma once
#include <string>

struct Color {
  uint8_t r, g, b;
  Color(uint8_t _r, uint8_t _g, uint8_t _b) : r(_r), g(_g), b(_b) {}
};

class Shape {
public:
  Shape(Color color) : m_color(color) {}

  virtual std::string toString() const {
    return "color="   std::to_string(m_color.r)   ','  
           std::to_string(m_color.g)   ','   std::to_string(m_color.b)   'n';
  }
  virtual float getArea() const = 0;
  virtual float getCircumference() const = 0;

  virtual ~Shape();

private:
  Color m_color;
};

// note: this method was moved here to satisfy the compiler's need for an
// out-of-line virtual function
Shape::~Shape() {}
  

Это один из 4 наследуемых заголовочных файлов (Square.h):

 #include "Shape.h"
#include <string>
class Square :
    public Shape
{
public:
    Square(Color rgb, float width) :Shape(rgb), w(width) {}
    std::string toString() {
        return Shape::toString()   'n'
              "width="   std::to_string(w)   'n';
    }
    float getArea() const override{
        return w*w;
    }
    float getCircumference() const override {
        return w*4;
    }
private:
    float w;
};
  

И это исходный файл для тестирования:

 #include <iostream>
#include <vector>

#include "Shape.h"
#include "Square.h"

void printAttributes(Shape amp;shape) {
    std::cout << shape.toString();
    ;
    std::cout << "area=" << std::to_string(shape.getArea()) << std::endl;
    std::cout << "circumference=" << std::to_string(shape.getCircumference())
        << 'n'
        << std::endl;
}

int main() {

    Color red{255, 0, 0 };
    Square square(red, 10.0);
    printAttributes(square);
    return 0;
}
  

например, вывод squares должен выглядеть следующим образом:

 color=255,0,0
width=10.000000
area=120.000000
circumference=44.000000
  

мой вывод показывает

 color=255,0,0
area=120.000000
circumference=44.000000
  

Комментарии:

1. @NathanOliver: Он вызывает shape.toString() то, что должно. Но код ни на йоту не соответствует ожидаемому результату.

2. Как я вижу, не существует версии Shape конструктора, которая принимает: Square(Color rgb, float width) :Shape(rgb), w(width) .

3. @MooingDuck Хорошие глаза.

4. const отсутствует в toString производном Square классе.

5. Последовательно используйте override ключевое слово при переопределении функций в производных классах (а затем отбросьте избыточные virtual ). Затем компилятор предупредит вас, когда вы неправильно получите сигнатуру функции и не фактически переопределите что-либо.

Ответ №1:

 class Square :
    public Shape
{
public:
    Square(Color rgb, float width) :Shape(rgb), w(width) {}
    std::string toString() const {
        return Shape::toString()   'n'
              "width="   std::to_string(w)   'n';
    }
    float getArea() const override{
        return w*w;
    }
    float getCircumference() const override {
        return w*4;
    }
private:
    float w;
};
  

Добавьте ключевое слово const после метода toString, тогда это переопределит вашу базовую функцию toString . foo() и foo() const не совпадают с формой вашего кодового вызова.toString(). В таблице виртуальных функций не будет переопределяться ваш метод Shape::toString.

Ответ №2:

Исправлен мой предыдущий ответ. Поскольку ваш базовый класс имеет const в сигнатуре функции, а производный класс — нет, функция toString производного класса фактически рассматривается как другая функция. Если вы добавляете const в производный класс или удаляете const из суперкласса, функция работает так, как задумано.

Комментарии:

1. полиморфизм также работает со ссылками, которые использует OP

2. Одна забавная особенность C в том, что VTables — это деталь реализации. Это простое и прямое решение проблемы, поэтому они обычно используются, но достаточно хитрый (или сумасшедший) программист мог бы реализовать полиморфизм с чем-то другим. Может быть, даже Lego.