I got a virtual method problem when trying code from https://en.wikipedia.org/wiki/Bridge_pattern.
Error messages are:
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
The code was compiled with g++ -o bridge bridge.cpp -std=c++11
Why drawing_api_.DrawCircle() called the virtual function in DrawingAPI?
#include <iostream>
#include <string>
#include <vector>
class DrawingAPI {
public:
virtual ~DrawingAPI() = default;
virtual std::string DrawCircle(float x, float y, float radius) const = 0;
};
class DrawingAPI01 : public DrawingAPI {
public:
std::string DrawCircle(float x, float y, float radius) const override {
return "API01.circle at " + std::to_string(x) + ":" + std::to_string(y) +
" - radius: " + std::to_string(radius);
}
};
class DrawingAPI02 : public DrawingAPI {
public:
std::string DrawCircle(float x, float y, float radius) const override {
return "API02.circle at " + std::to_string(x) + ":" + std::to_string(y) +
" - radius: " + std::to_string(radius);
}
};
class Shape {
public:
Shape(const DrawingAPI& drawing_api) : drawing_api_(drawing_api) {}
virtual ~Shape() = default;
virtual std::string Draw() const = 0;
virtual float ResizeByPercentage(const float percent) = 0;
protected:
const DrawingAPI& drawing_api_;
};
class CircleShape: public Shape {
public:
CircleShape(float x, float y, float radius, const DrawingAPI& drawing_api)
: Shape(drawing_api), x_(x), y_(y), radius_(radius) {}
std::string Draw() const override {
return drawing_api_.DrawCircle(x_, y_, radius_);
}
float ResizeByPercentage(const float percent) override {
return radius_ *= (1.0f + percent/100.0f);
}
private:
float x_, y_, radius_;
};
int main(int argc, char** argv) {
std::vector<CircleShape> shapes {
CircleShape{1.0f, 2.0f, 3.0f, DrawingAPI01{}},
CircleShape{5.0f, 7.0f, 11.0f, DrawingAPI02{}}
};
for (auto& shape: shapes) {
shape.ResizeByPercentage(2.5);
std::cout << shape.Draw() << std::endl;
}
return 0;
}
The posted code is buggy -- in particular, the Shape class is holding a reference-to-a-DrawingAPI-object:
class Shape {
[...]
protected:
const DrawingAPI& drawing_api_;
};
... but the object that it is referencing is a temporary that gets destroyed as soon as the CircleShape constructors inside main() return.
One way to avoid the fault would be to declare the DrawingAPI01 and DrawingAPI02 objects in such a way that their lifetimes last longer than the lifetimes of the CircleShape objects that reference them, e.g. by changing main() to look like this:
int main(int argc, char** argv) {
DrawingAPI01 api01; // declaring these up here keeps them valid
DrawingAPI01 api02; // until the end of main()
std::vector<CircleShape> shapes {
CircleShape{1.0f, 2.0f, 3.0f, api01},
CircleShape{5.0f, 7.0f, 11.0f, api02}
};
for (auto& shape: shapes) {
shape.ResizeByPercentage(2.5);
std::cout << shape.Draw() << std::endl;
}
return 0;
}
Related
I am trying to figure out how to find the axis of class Square's axis as shown below? But I've been trying for hours and still did not managed to solve it. Can someone with their high level expertise show me the ropes to do it? Because both center function call and axis function call in main() does call the same x() and y(), hence brought me to a state of confusion. I know the inheritance of square from circle is weird. But it is what my school wants. Note: Main() CANNOT be modified! Thanks!
Output:
Square::axis test failed
8.87627 0.284967
3.82567 0.958537
Tests passed: 50%
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
class Object
{
public:
private:
float d;
public:
Object(float n) : d(n){}
Object(){}
float depth() const
{
return d;
}
struct PointType
{
float x2;
float y2;
PointType( float x1, float y1) :x2(x1),y2(y1){}
PointType(){}
float x()
{
return x2;
}
float y()
{
return y2;
}
PointType center()
{
return *this;
}
};
struct VectorType
{
float tx;
float ty;
VectorType( float tx1, float ty1) :tx(tx1),ty(ty1){}
VectorType( ){}
};
virtual ~Object()
{}
};
class Point :public Object
{
private:
PointType mpoint;
public:
Point(const PointType& pt, float& y1) :Object(y1), mpoint(pt) {}
Point(const PointType& pt):mpoint(pt){}
Point(){}
Point center() const
{
return *this;
}
float x()
{
return mpoint.x2;
}
float y()
{
return mpoint.y2;
}
virtual ~Point(){}
};
class Circle : public Point
{
private:
Object::PointType m_pt;
float r;
public:
Circle(const PointType pts, float rad, float dep)
: Point(m_pt,dep),m_pt(pts),r(rad) {}
Circle(const PointType pts, float rad):m_pt(pts),r(rad){}
Circle(){}
float radius() const
{
return r;
}
Circle center() const
{
return *this;
};
float x()
{
return m_pt.x2;
}
float y()
{
return m_pt.y2;
}
};
class Square: public Circle
{
private:
Object::PointType s_pt;
Object::VectorType v_pt;
float a=getRadius();
public:
Square(const PointType spts,const VectorType vpts,float depth) :
Circle(spts,a,depth),s_pt(spts),v_pt(vpts){}
Square(const Object::PointType& spts, const VectorType vpts):s_pt(spts),v_pt(vpts){}
Square axis() const
{
return Square(s_pt,v_pt,getRadius());
}
Square center() const
{
return *this;
}
float radius() const
{
return a;
}
float getRadius() const
{
float rad= sqrt(v_pt.tx * v_pt.tx + v_pt.ty * v_pt.ty);
return rad;
}
float x() const
{
return s_pt.x2;
// v_pt.tx/radius();
}
float y() const
{
return s_pt.y2;
// v_pt.ty/radius();
}
};
const float EPSILON = 1e-5f;
bool is_near(float x, float y)
{
return std::abs(x - y) < EPSILON;
}
float frand()
{
return 10.0f * float(rand()) / float(RAND_MAX);
}
int main()
{
srand(unsigned(time(0)));
int count = 0;
int max_count = 0;
float x = frand();
float y = frand();
float sx = frand();
float sy = frand();
float depth = frand();
Square square(Square::PointType(x, y), Square::VectorType(sx, sy), depth);
if (is_near(square.center().x(), x) &&
is_near(square.center().y(), y))
{
++count;
}
else
{
std::cout << " - Square::center test failed" << std::endl;
}
++max_count;
float radius = std::sqrt(sx * sx + sy * sy);
if (is_near(square.axis().x(), sx / radius) &&
is_near(square.axis().y(), sy / radius))
{
++count;
}
else
{
std::cout << " - Square::axis test failed" << std::endl;
}
++max_count;
std::cout << square.axis().x()<< " " << sx / radius<<std::endl;
std::cout << square.axis().y()<< " " << sy / radius<<std::endl;
int result = static_cast<int>(
100.0f * static_cast<float>(count) / static_cast<float>(max_count) + 0.5f
);
std::cout << "Tests passed: " << result << "%" << std::endl;
return result;
}
I have a list of derived class objects of 3 types, each contains string and two integers.
#include "pch.h"
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <iterator>
class Shape
{
private:
int x, y;
public:
Shape() {}
Shape(int &x_, int &y_) : x(x_), y(y_) {}
virtual void Draw() {
std::cout << this->x << ", " << this->y << "}\n";
}
};
class Circle : public Shape
{
private:
std::string type;
public:
Circle() {}
Circle(int &x_, int &y_) : Shape(x_, y_) { this->type = "Circle"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
class Triangle : public Shape
{
private:
std::string type;
public:
Triangle() {}
Triangle(int &x_, int &y_) : Shape(x_, y_) { this->type = "Triangle"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
class Square : public Shape
{
private:
std::string type;
public:
Square() {}
Square(int &x_, int &y_) : Shape(x_, y_) { this->type = "Square"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
void FillWithShapes(int n, std::list<Shape*> &ls) {
int x, y, type;
Circle cir;
Triangle tri;
Square sq;
for (int i = 0; i < 10; i++) {
type = rand() % 3;
x = rand() % 100;
y = rand() % 100;
if (type == 0) {
cir = Circle(x, y);
ls.push_back(&cir);
}
else if (type == 1) {
tri = Triangle(x, y);
ls.push_back(&tri);
}
else if (type == 2) {
sq = Square(x, y);
ls.push_back(&sq);
}
}
}
int main()
{
std::list<Shape*> shapes;
FillWithShapes(10, shapes);
std::for_each(shapes.begin(), shapes.end(), [](Shape *s) { s->Draw(); });
}
I'm getting read access violation exception when accessing list elements in lambda:
Exception thrown: read access violation.
s->**** was 0xCCCCCCCC.
But when I put the code from function FillWithShapes straight to main(), it works just fine:
Square: {18, 95}
Triangle: {82, 21}
Circle: {2, 53}
Square: {18, 95}
Triangle: {82, 21}
Square: {18, 95}
Circle: {2, 53}
Circle: {2, 53}
Triangle: {82, 21}
Square: {18, 95}
I have started learning c++ not long ago, so I have no idea what may cause this exception in this case, though I'm probably missing something simple but significant here.
UPD:
Fixed function to create pointers on heap:
void FillWithShapes(int n, std::list<Shape*> &ls) {
int x, y, type;
Circle *cir = new Circle();
Triangle *tri = new Triangle();
Square *sq = new Square();
for (int i = 0; i < 10; i++) {
type = rand() % 3;
x = rand() % 100;
y = rand() % 100;
if (type == 0) {
*cir = Circle(x, y);
ls.push_back(cir);
}
else if (type == 1) {
*tri = Triangle(x, y);
ls.push_back(tri);
}
else if (type == 2) {
*sq = Square(x, y);
ls.push_back(sq);
}
}
}
In your function FillWithShapes, you are creating objects of type Circle, Sqaure etc and pushing those pointers into the vector. Once that function goes out of scope, these pointers are no longer valid.
You could create the objects on the heap and push those in the vector with the burden of de-allocating once done with the vector.
You're filling the list with pointers to variables local to your FillWithShapes() function and stored on the stack. Their lifetime ends after the function returns - so it's reasonable that you get an access violation.
When you hoist the code up to main(), the lifetime of the local variables is now the lifetime of main(), i.e. throughout your program and past your last accesses through the list of shapes - so no violation.
You might want to read: What and where are the stack and heap?
When I run this code and create an instance of cylinderType by passing four parameters, debugger shows the height I want but, radius=x=y=0. So when I call method printVolume() on this object, it displays '0'.
Am I missing something important with inheritance?
Thank you~
#include <iostream>
using namespace std;
class circleType
{
public:
circleType();
circleType(double r);
double getArea() const;
private:
double radius;
};
class cylinderType : public circleType
{
public:
cylinderType(double h, double r);
void printVolume() const;
private:
double height;
};
int main()
{
cylinderType cylinderA(2, 4);
cylinderA.printVolume();
return 0;
};
circleType::circleType()
{
radius = 0;
};
circleType::circleType(double r)
{
radius = r;
};
double circleType::getArea() const
{
return (3.14 * radius* radius);
};
cylinderType::cylinderType(double h, double r)
{
circleType::circleType(r);
height = h;
};
void cylinderType::printVolume() const
{
cout << (circleType::getArea() * height);
};
I dont understand the diffrence between Polymorphism and Inheritance... They Litterarly do the same thing...
Simple Example Of Polymorphism:
class shape {
public:
void setValues(int height_, int width_) {
height = height_, width = width_;
}
protected:
int height, width;
private:
};
class rectangle :public shape, public ThreeDView{
public:
int area() {
return(shape::height*shape::width);
}
float threeDArea() {
return(((shape::height*shape::width)/2)*(std::cos(Z_LENGTH)));
}
};
class ThreeDView{
public:
void setZLength(int value) {
Z_LENGTH = value;
}
int setCompact(bool ans) {
compact = ans;
}
float getZLength() {
return Z_LENGTH;
}
bool getCOMPACT() {
return compact;
}
protected:
float Z_LENGTH;
bool compact;
private:
unsigned char ZCHAR = 'Z';
};
class triangle :public shape {
public:
int area() {
return((shape::height * shape::width) / 2);
}
};
int main(){
rectangle rect2;
triangle trng2;
shape *poly = &rect2;
shape *poly2 = &trng2;
poly->setValues(2,3);
poly2->setValues(5,4);
std::cout << "AREA : " << trng1.area() << "AREA RECT : \n" <<rect1.area() << std::endl;
}
Above example translated to Inheritance:
class shape {
public:
void setValues(int height_, int width_) {
height = height_, width = width_;
}
protected:
int height, width;
private:
};
class rectangle :public shape, public ThreeDView{
public:
int area() {
return(shape::height*shape::width);
}
float threeDArea() {
return(((shape::height*shape::width)/2)*(std::cos(Z_LENGTH)));
}
};
class triangle :public shape {
public:
int area() {
return((shape::height * shape::width) / 2);
}
};
int main(){
rectangle rect2;
triangle trng2;
rect2.setValues(2,3);
trng2.setValues(5,4);
std::cout << "AREA : " << trng1.area() << "AREA RECT : \n" <<rect1.area() << std::endl;
}
Please tell me diffrence. Honestly i dont even see the use of Polymorphism! Thanks for helping!
Here's a version of your first example, that actually uses polymorphism:
#include <iostream>
#include <string>
class shape
{
public:
void setValues(int height_, int width_)
{
height = height_;
width = width_;
}
virtual int area() = 0; // This is needed for polymorphism to work
virtual std::string name() = 0;
protected:
int height;
int width;
};
class rectangle : public shape
{
public:
int area()
{
return height * width;
}
std::string name()
{
return "Rectangle";
}
};
class triangle :public shape
{
public:
int area()
{
return height * width / 2;
}
std::string name()
{
return "Triangle";
}
};
void print_area(shape& poly)
{
std::cout << poly.name() << ' ' << poly.area() << '\n';
}
int main()
{
rectangle rect;
triangle trng;
rect.setValues(2, 3);
trng.setValues(5, 4);
print_area(rect);
print_area(trng);
}
The first big change is that I declare the virtual function area in the shape class. For polymorphism to work, the functions must be declared in the base class as virtual. The "assignment" to 0 is simply telling the compiler that it's an abstract function, and the child-classes must override that function.
The second big change is that I use a function to print the area, one that only takes a reference to the base shape class. You must use references or pointers to the base class for polymrphism to work, not use the actual objects directly like in your example.
This works as expected.
I am learning OpenGL w/ C++. I am building the asteroids game as an exercise. I'm not quite sure how to override the constructors:
projectile.h
class projectile
{
protected:
float x;
float y;
public:
projectile();
projectile(float, float);
float get_x() const;
float get_y() const;
void move();
};
projectile.cpp
projectile::projectile()
{
x = 0.0f;
y = 0.0f;
}
projectile::projectile(float X, float Y)
{
x = X;
y = Y;
}
float projectile::get_x() const
{
return x;
}
float projectile::get_y() const
{
return y;
}
void projectile::move()
{
x += 0.5f;
y += 0.5f;
}
asteroid.h
#include "projectile.h"
class asteroid : public projectile
{
float radius;
public:
asteroid();
asteroid(float X, float Y);
float get_radius();
};
main.cpp
#include <iostream>
#include "asteroid.h"
using namespace std;
int main()
{
asteroid a(1.0f, 2.0f);
cout << a.get_x() << endl;
cout << a.get_y() << endl;
}
error I'm getting:
main.cpp:(.text+0x20): undefined reference to `asteroid::asteroid(float, float)'
You can use the : syntax to call the parent's constructor:
asteroid(float X, float Y) : projectile (x ,y);
Ok, just figured it out.
I actually don't have asteroid constructors defined because I thought they would inherit. But I think I have to do the following in asteroid.h:
asteroid(float X, float Y) : projectile(X, Y){];
You need a asteroid.cpp.
Even though inheriting from projectile, for non-default constructors (i.e., asteroid(float,float)), you still need to define the child class constructor.
You'll also need to define get_radius, as it's not defined in your base class.
Here's how that might look (I've taken the liberty of passing values for radius into both ctors):
#include "asteroid.h"
asteroid::asteroid(float r)
: projectile()
{
radius = r;
}
asteroid::asteroid(float x, float y, float r)
: projectile(x, y)
{
radius = r;
}
float asteroid::get_radius()
{
return radius;
}