I am still new to programming as a subject and I realised that I need to ask for help. Please be patient with me.
For this assignment I have to implement virtual construction using the factory method design pattern and Virtualization of non-member functions (via delegation to a virtual member function).
The construct() function will create a formatter object (Text, Markdown or Html) based on choice and will create headers, paragraphs and block quotes. The global function save() saves the text element into a stream. The files included are the only ones permitted to be used.
Thank you to those that answered previously.
The main.cpp file below contains the driver code from my professor:
#include "MemoryAlloc.h"
#include "Constructor.h"
void process(IFormatterElement* const element)
{
if (element)
{
try
{
if (ISavable* const savable = dynamic_cast<ISavable* const>(element))
{
save(*savable, std::cout);
}
delete element;
}
catch (...)
{
delete element;
throw;
}
}
}
int main()
{
std::cerr << "Choose a formatter:\n";
std::vector<std::string> options = get_options();
for (size_t i = 0; i < options.size(); ++i)
{
std::cerr << "\t" << (i + 1) << ". " << options[i] << "\n";
}
std::cerr
<< "\tother to exit\n"
<< "Your choice: ";
int selected_option;
if (std::cin >> selected_option)
{
if (IFormatterFactory* factory = construct(--selected_option))
{
std::cerr << "\nYou chose \"" << options[selected_option] << "\"." << std::endl;
try
{
process(factory->create_begin());
process(factory->create_header1("Assignment result"));
process(factory->create_paragraph("This file represents an assignment result."));
process(factory->create_header2("Initial paragraph"));
process(factory->create_paragraph("This is the first paragraph of the result file."));
process(factory->create_header2("Final paragraph"));
process(factory->create_paragraph("This is the second paragraph of the result file."));
process(factory->create_blockquote("This is a quote."));
process(factory->create_paragraph("This is the third paragraph of the result file."));
process(factory->create_paragraph("This is the last paragraph of the result file."));
process(factory->create_end());
}
catch (...)
{
std::cerr << "An exception has been thrown!" << std::endl;
}
delete factory;
}
else
{
std::cerr << "Exiting..." << std::endl;
}
}
}
Interface class IFormatterelement.h to support operations needed in process() as defined by me.
#ifndef _IFORMATTERELEMENT_H_
#define _IFORMATTERELEMENT_H_
class IFormatterElement
{
public:
virtual ~IFormatterElement() = default;
};
#endif // _IFORMATTERELEMENT_H_
Interface class IFormatterfactory.h to support operations needed in main() as defined by me.
#ifndef _IFORMATTERFACTORY_H_
#define _IFORMATTERFACTORY_H_
#include <string>
#include "IFormatterElement.h"
class IFormatterFactory : public IFormatterElement
{
public:
virtual IFormatterFactory* create_begin() = 0;
virtual IFormatterFactory* create_end() = 0;
virtual IFormatterFactory* create_header1(const std::string& text) = 0;
virtual IFormatterFactory* create_header2(const std::string& text) = 0;
virtual IFormatterFactory* create_paragraph(const std::string& text) = 0;
virtual IFormatterFactory* create_blockquote(const std::string& text) = 0;
};
#endif // _IFORMATTERFACTORY_H_
Interface class ISavable.h to be realized by classes that saves into a stream.
#ifndef _ISAVABLE_H_
#define _ISAVABLE_H_
#include <iostream>
struct ISavable
{
virtual void save(std::ostream& stream) = 0;
virtual ~ISavable() = default;
};
#endif // _ISAVABLE_H_
Global functions that are needed. IFormatterFactory* construct(int selected_option);
is the factory method and void save(ISavable& savable, std::ostream& stream);
will be a polymorphic call to save into a stream
#ifndef _CONSTRUCTOR_H_
#define _CONSTRUCTOR_H_
#include <iostream>
#include <vector>
#include <string>
#include "IFormatterFactory.h"
#include "ISavable.h"
// Produces a list of available formatter names.
std::vector<std::string> get_options();
// Constructs a formatter based on the index of its name from get_options().
IFormatterFactory* construct(int selected_option);
// Saves an object to a stream.
void save(ISavable& savable, std::ostream& stream);
#endif // _CONSTRUCTOR_H_
Below is my implementation of Constructor.cpp
#include "Constructor.h"
#include "Text.h"
#include "Markdown.h"
#include "Html.h"
std::vector<std::string> get_options()
{
std::vector<std::string> formatters;
formatters.push_back("Text");
formatters.push_back("Markdown");
formatters.push_back("Html");
return formatters;
}
IFormatterFactory* construct(int selected_option)
{
if(selected_option == 0)
return new Text;
if(selected_option == 1)
return new Markdown;
else
return new Html;
}
void save(ISavable& savable, std::ostream& stream)
{
savable.save(stream);
}
My implementation of Text class and its member functions.
#ifndef _TEXT_H_
#define _TEXT_H_
#include "ISavable.h"
#include "IFormatterFactory.h"
class Text : public IFormatterFactory, public ISavable
{
public:
Text();
Text* create_begin();
Text* create_end();
void save(std::ostream& stream);
Text* create_header1(const std::string& text);
Text* create_header2(const std::string& text);
Text* create_paragraph(const std::string& text);
Text* create_blockquote(const std::string& text);
private:
std::string _input;
};
Text::Text() : _input{}
{
}
Text* Text::create_begin()
{
return this;
}
Text* Text::create_end()
{
return this;
}
Text* Text::create_header1(const std::string& text)
{
_input = text + "\n";
return this;
}
Text* Text::create_header2(const std::string& text)
{
_input = + "\n" + text + "\n";
return this;
}
Text* Text::create_paragraph(const std::string& text)
{
_input = text + "\n";
return this;
}
Text* Text::create_blockquote(const std::string& text)
{
_input = "\"" + text + "\"" + "\n";
return this;
}
void Text::save(std::ostream& stream)
{
stream << _input;
}
#endif
My implementation of Markdown class and its member functions.
#ifndef _MARKDOWN_H_
#define _MARKDOWN_H_
#include "ISavable.h"
#include "IFormatterFactory.h"
class Markdown : public IFormatterFactory, public ISavable
{
public:
Markdown();
Markdown* create_begin();
Markdown* create_end();
void save(std::ostream& stream);
Markdown* create_header1(const std::string& text);
Markdown* create_header2(const std::string& text);
Markdown* create_paragraph(const std::string& text);
Markdown* create_blockquote(const std::string& text);
private:
std::string _input;
char _count{1};
};
Markdown::Markdown() : _input{}
{
}
Markdown* Markdown::create_begin()
{
return this;
}
Markdown* Markdown::create_end()
{
return this;
}
Markdown* Markdown::create_header1(const std::string& text)
{
_input = std::string("\n") + std::string("# 1. ") + text + "\n";
return this;
}
Markdown* Markdown::create_header2(const std::string& text)
{
_input = std::string("\n") + std::string("## 1.") + (_count++) + ". " + text + "\n";
return this;
}
Markdown* Markdown::create_paragraph(const std::string& text)
{
_input = text + "\n";
return this;
}
Markdown* Markdown::create_blockquote(const std::string& text)
{
_input = + "> " + text + "\n\n";
return this;
}
void Markdown::save(std::ostream& stream)
{
stream << _input;
}
#endif
My implementation of Html class
#ifndef _HTML_H_
#define _HTML_H_
#include "ISavable.h"
#include "IFormatterFactory.h"
class Html : public IFormatterFactory, public ISavable
{
public:
Html();
Html* create_begin();
Html* create_end();
void save(std::ostream& stream);
Html* create_header1(const std::string& text);
Html* create_header2(const std::string& text);
Html* create_paragraph(const std::string& text);
Html* create_blockquote(const std::string& text);
private:
std::string _input;
char _count{1};
char _end{1};
};
Html::Html() : _input{}
{
}
Html* Html::create_begin()
{
_input = std::string("<!doctype html>") + "\n" + "<html lang=en>" + "\n"
+ "<style>blockquote { border-left: 4px solid #d0d0d0; "
+ "padding: 4px; }</style>"
+ "\n" + "<head>" + "\t<meta charset=utf-8>"
+ "\n" + "\t<title>Result</title>"
+ "</head>\n" + "<body>\n";
return this;
}
Html* Html::create_end()
{
return this;
}
Html* Html::create_header1(const std::string& text)
{
_input = "\t<h1>1. " + text + "</h1>" + "\n";
return this;
}
Html* Html::create_header2(const std::string& text)
{
_input = std::string("\t<h2>1.") + (_count++) + std::string(". ") + text + "</h2>" + "\n";
return this;
}
Html* Html::create_paragraph(const std::string& text)
{
_input = "\t<p>" + text + "</p>" + "\n";
if(_end==5)
{
_input + "</body>" + "\n";
_input + "</html>" + "\n";
}
else
{
_end++;
}
return this;
}
Html* Html::create_blockquote(const std::string& text)
{
_input = "\t<blockquote>" + text + "</blockquote>" + "\n";
return this;
}
void Html::save(std::ostream& stream)
{
stream << _input;
}
#endif
My idea was to use std::string to store the lines or characters and save it into
std::ostream& stream` but when I compile the program, I will get SEGMENTATION FAULT for all 3 formatter classes.
I used gdb to find out the cause of the SEGMENTATION FAULT. I got this message:
Choose a formatter:
1. Text
2. Markdown
3. Html
other to exit
Your choice: 3
You chose "Html".
<!doctype html>
<html lang=en>
<style>blockquote { border-left: 4px solid #d0d0d0; padding: 4px; }</style>
<head> <meta charset=utf-8>
<title>Result</title></head>
<body>
Thread 1 "main" received signal SIGSEGV, Segmentation fault.
0x0000000180325278 in _gm_ () from /usr/bin/cygwin1.dll
(gdb) quit
I figured the cause of this error is the call to process(factory>create_begin()); in main() as given by my prof, which I cannot change.
I am truly stuck at this point of time. I could not reach my professor for help so I am reaching out to the online community for help. Is the member function create_begin() implemented wrongly in my Text, Markdown and Html class?
Aucun commentaire:
Enregistrer un commentaire