Static member declaration in Parametrized polymorphism - c++

I have gender class with Male and Female as my parametric types of class
I am using following hierarchy:
#ifndef __GENDER_H
#define __GENDER_H
#include <string>
using namespace std;
// Forward declaration of templatized class
template<typename T>
class GenderTypes; // Generic Gender type to generate specific genders
// Generic gender type
class Gender { // Abstract Base Class
const string& name_; // Name of the Gender
struct MaleType {};
struct FemaleType {};
protected:
Gender(const string& name) : name_(name) {}
virtual ~Gender() { }
public:
const string& GetName() const { return name_; }
bool IsMale(const Gender&); // Checking and matching gender
// Enumerated types - the target sub-types
typedef GenderTypes<MaleType> Male;
typedef GenderTypes<FemaleType> Female;
};
// Specific gender types
template<typename T>
class GenderTypes : public Gender {
static const string sName;
GenderTypes(const string& name = GenderTypes<T>::sName) : Gender(name) { }
~GenderTypes() { }
public:
// Singleton object - placeholder for the respective type
static const GenderTypes<T>& Type() {
static const GenderTypes<T> theObject; // May be non-const for changeable behavior
return theObject;
}
};
inline bool Gender::IsMale(const Gender& g) { return &g == &Gender::Male::Type(); }
#endif
And declaring the static member name_ as follows:
#include <string>
using namespace std;
#include "../inc/gender.h"
// Names defined as static constants
const string Gender::Male::sName = "Male";
const string Gender::Female::sName = "Female";
This kind of hierarchy is fine . then why compiler gives this error:
gender.cpp:5:14: error: specializing member ‘GenderTypes<Gender::MaleType>::sName’ requires ‘template<>’ syntax
5 | const string Gender::Male::sName = "Male";
how should i initialize this static datas?
I am using VS CODE editor and Ubuntu 20.04

With this small change in your .cpp it compiles (and works) fine on my machine :
template<>
const string Gender::Male::sName = "Male";
template<>
const string Gender::Female::sName = "Female";
And indeed in your header you should use
#ifndef GENDER_H
#define GENDER_H
[...]
#endif
OR
#pragma once
[...]

Related

In function undefined reference c++

I get a strange error all the time.
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:
In function _start: >(.text+0x20): undefined reference to main
/tmp/cc4ZqKzy.o:
In function `Sep::Building::Building(Sep::Field::FieldType, >std::__cxx11::basic_string, >std::allocator >, char, bool, bool, unsigned int, unsigned int):
Building.cpp:(.text+0x3c): undefined reference to Sep::Field::Field()
collect2:
error: ld returned 1 exit status
I read a lot with this problem but none had the same. I included all the headers and also added ifndef guards.
main.cpp:
#include "Field.h"
#include "Building.h"
namespace Sep
{
just some returns...
}
int main(int argc, char *argv[])
{
Sep::Building Haus(Sep::Field::FieldType::HOME,"HOME", 'H', true, true, 100, 100);
std::cout << "HAUS ABREV:" << Haus.getAbbrevationOnField() << '\n';
}
Field.h
#include <cstring>
#include <string>
#include <iostream>
#include <memory>
#ifndef FIELD_H
#define FIELD_H
namespace Sep
{
//----------------------------------------------------------------------------
// Field class, containing all needed information to create a Field object
//
class Field
{
public :
enum FieldType \
{GRASS, WATER, OBSTACLE, STREET, HOME, MARKET, CLINIC, TOWNHALL};
private:
FieldType type_;
std::string name_;
char abbrevation_;
bool buildable_;
bool destroyable_;
unsigned int build_cost_;
unsigned int destroy_cost_;
public:
//------------------------------------------------------------------------
// Field constructors & destructor
//
Field();
Field(FieldType type);
~Field() noexcept;
//------------------------------------------------------------------------
//getters
//
Field::FieldType getFieldType() const { return type_; };
const char getAbbrevationOnField() const { return abbrevation_; };
//------------------------------------------------------------------------
//setters
//
static std::string getName(FieldType type);
FieldType getType() const;//steht oben in getFiel3dType Z55
void setType(FieldType type){type_ = type;};
void setName(std::string name){name_ = name;};
void setAbbrevation(char abbrev){abbrevation_ = abbrev;};
void setBuildable(bool buildable){buildable_ = buildable;};
void setDestroyable(bool destroyable){destroyable_ = destroyable;};
void setBuildCost(int b_cost){build_cost_ = b_cost;};
void setDestroyCost(int d_cost){destroy_cost_ = d_cost;};
};
}
#endif //FIELD.H
Field.cpp
#include "Field.h"
#include <cstring>
#include <string>
#include <iostream>
#include <memory>
using Sep::Field;
//------------------------------------------------------------------------------
// Setter of the private FieldType type_ to the given param
//
// #param the type of field to get set
//
Field::Field(FieldType type)
{
type_ = type;
};
Field::~Field(){};
//------------------------------------------------------------------------------
// Checks the type of a given field, returns the name of type as string
//
// #param type, the type of the field to check
//
// #return string the name of the type of the checked field
//
std::string Field::getName(FieldType type)
{
switch (type)
{
case GRASS:
return std::string("Grass");
case WATER:
return std::string("Water");
case OBSTACLE:
return std::string("Obstacle");
case STREET:
return std::string("Street");
case HOME:
return std::string("Home");
case MARKET:
return std::string("Market");
case CLINIC:
return std::string("Clinic");
case TOWNHALL:
return std::string("Town Hall");
default:
return std::string("Unknown Field");
}
};
//------------------------------------------------------------------------------
// getters
//
// Getter from the private FieldType type_
//
// #param none
//
// #return the type of type_ as FieldType
//
Field::FieldType Field::getType() const
{
return type_;
};
Building.h
#ifndef BUILDING_H
#define BUILDING_H
#include "Field.h"
namespace Sep
{
class Building : public Field
{
private:
public:
Building(FieldType type, const std::string name, const char abbrevation, \
const bool buildable, const bool destroyable,\
const unsigned int b_cost, const unsigned int d_cost);
~Building();
};
}
#endif //BUILDING_H
Building.cpp
#include "Building.h"
#include "Field.h"
Sep::Building::Building(FieldType type, const std::string name, \
const char abbrevation, \
const bool buildable, const bool destroyable,\
const unsigned int b_cost, const unsigned int d_cost)
{
Sep::Field::setType(type);
Sep::Field::setName(name);
Sep::Field::setAbbrevation(abbrevation);
Sep::Field::setBuildable(buildable);
Sep::Field::setDestroyable(destroyable);
Sep::Field::setBuildCost(b_cost);
Sep::Field::setDestroyCost(d_cost);
};
Sep::Building::~Building(){};
Has anyone a idea? Cause I get this error often in this project but in other classes.
The strange thing is that it seems like, that the program compiles correctly but on the start I get this collect2: error: ld returned 1 exit status.
Thx
Field.cpp need to be changed, if don't want to used Field() constructor just put the definition of Field() constructor empty.
For examples:
Field.cpp
#include "Field.h"
#include <cstring>
#include <string>
#include <iostream>
#include <memory>
using Sep::Field;
//------------------------------------------------------------------------------
// Setter of the private FieldType type_ to the given param
//
// #param the type of field to get set
//
Field::Field(){
//empty constructor or can initialize type_ to default value.
}
Field::Field(FieldType type)
{
type_ = type;
};
Field::~Field(){};
//------------------------------------------------------------------------------
// Checks the type of a given field, returns the name of type as string
//
// #param type, the type of the field to check
//
// #return string the name of the type of the checked field
//
std::string Field::getName(FieldType type)
{
switch (type)
{
case GRASS:
return std::string("Grass");
case WATER:
return std::string("Water");
case OBSTACLE:
return std::string("Obstacle");
case STREET:
return std::string("Street");
case HOME:
return std::string("Home");
case MARKET:
return std::string("Market");
case CLINIC:
return std::string("Clinic");
case TOWNHALL:
return std::string("Town Hall");
default:
return std::string("Unknown Field");
}
};
//------------------------------------------------------------------------------
// getters
//
// Getter from the private FieldType type_
//
// #param none
//
// #return the type of type_ as FieldType
//
Field::FieldType Field::getType() const
{
return type_;
};
When you are trying to construct a Building, the Building::Building(...) constructor implicitly calls its base class constructor Field::Field() (since you did not specify which Field constructor you want). You promised in Field.h that such a constructor exists somewhere (which is why the compiler never complains), but you never define it. When the linker then tries to link the functions you declared with the functions that the compiler emitted, it notices that this constructor is missing and complains.
This is what the error messages are trying to tell you:
undefined reference to 'Sep::Field::Field()' -> The Field::Field() constructor is not defined anywhere.
In function Sep::Building::Building(...) -> It is trying to call the Field constructor in the shown Building constructor.
The simplest fix is to write Field() = default; so the compiler automatically generates the default constructor.
Edit: If you want to use the Field::Field(FieldType) constructor, this is how you would do that:
Building::Building(FieldType fieldType, /* etc */)
: Field(fieldType)
{
// etc.
}
You could also add a constructor to the Field class that takes all these arguments that you are trying to pass:
Field::Field(FieldType fieldType, std::string name, char abbrevation, /* etc. */)
: type_(fieldType), name_(name), abbrevation_(abbreviation), /* etc. */
{
}
And thus:
Building::Building(FieldType type, const std::string name, const char abbrevation, /* etc. */)
: Field(type, name, abbreviation, /* etc. */)
{
}
Even better, you can just "reuse" the long Field constructor for Building
class Building : public Field
{
public:
using Field::Field;
// ...
}

Why does standalone method from header file needs to be namespace qualified, when class methods do not?

I've been debugging code that wouldn't link, since the symbol dev::solidity::CreateEmptyFuncDef couldn't be found when defined as CreateEmptyFuncDef in ASTUtils.cpp (return type and parameters are omitted).
But why does CreateEmptyFunc needs to be qualified by dev::solidity, when the defined LocationFinder class methods aren't?
I thought that using dev::solidity was sufficient, so that namespace qualifiers may be left out?
ASTUtils.h:
#pragma once
#include <libevmasm/SourceLocation.h>
#include <libsolidity/ast/ASTVisitor.h>
#include <string>
namespace dev
{
namespace solidity
{
class LocationFinder: private ASTConstVisitor
{
public:
LocationFinder(SourceLocation const& _location, std::vector<ASTNode const*> _rootNodes):
m_rootNodes(_rootNodes), m_location(_location)
{
}
/// #returns the "closest" (in the sense of most-leafward) AST node which is a descendant of
/// _node and whose source location contains _location.
ASTNode const* leastUpperBound();
private:
bool visitNode(ASTNode const& _node);
std::vector<ASTNode const*> m_rootNodes;
SourceLocation m_location;
ASTNode const* m_bestMatch = nullptr;
};
ASTPointer<FunctionDefinition> CreateEmptyFuncDef(const std::string name, const std::string sourcePath);
}
}
ASTUtils.cpp:
#include <libsolidity/ast/ASTUtils.h>
using namespace std;
using namespace dev;
using namespace dev::solidity;
ASTNode const* LocationFinder::leastUpperBound()
{
m_bestMatch = nullptr;
for (ASTNode const* rootNode: m_rootNodes)
rootNode->accept(*this);
return m_bestMatch;
}
bool LocationFinder::visitNode(const ASTNode& _node)
{
if (_node.location().contains(m_location))
{
m_bestMatch = &_node;
return true;
}
return false;
}
ASTPointer<FunctionDefinition> dev::solidity::CreateEmptyFuncDef(const string name, const string sourcePath) {
SourceLocation _loc(0, 0, make_shared<ASTString>(sourcePath));
ASTPointer<ASTString> _name = make_shared<ASTString>(name);
Declaration::Visibility _visibility = Declaration::Visibility::Public;
StateMutability _mutability = StateMutability::NonPayable;
bool _isConstructor = false;
ASTPointer<ASTString> _doc = make_shared<ASTString>();
std::vector<ASTPointer<VariableDeclaration>> _varDecs;
ASTPointer<ParameterList> _params = make_shared<ParameterList>(_loc, _varDecs);
std::vector<ASTPointer<ModifierInvocation>> _mods;
ASTPointer<ParameterList> _retParams = make_shared<ParameterList>(_loc, _varDecs);
std::vector<ASTPointer<Statement>> _statements;
ASTPointer<Block> _body = make_shared<Block>(_loc, _doc, _statements); // empty block
return make_shared<FunctionDefinition>(_loc, _name, _visibility, _mutability, _isConstructor, _doc, _params, _mods, _retParams, _body);
}
using namespace directive makes existing name available to current namespace but it doesn't forbid you to define new name, i.e. name that doesn't conflict with existing names. When you do something like this in global namespace:
ASTPointer<FunctionDefinition> CreateEmptyFuncDef(const string name, const string sourcePath) {
//
}
It declares and defines a new function CreateEmptyFuncDef which is different from previously declared dev::solidity::CreateEmptyFuncDef.
To avoid the dev::solidity:: qualification you can enclose this function inside dev::solidity namespace like this:
namespace dev {
namespace solidity {
ASTPointer<FunctionDefinition> CreateEmptyFuncDef(const string name, const string sourcePath) {
//
}
}
}
That will define dev::solidity::CreateEmptyFuncDef without introducing a new name.
The class name should have been qualified with namespace too. For example, consider the following minimum code:
namespace foo {
class Bar {
void baz();
};
}
void Bar::baz() {}
int main() {
}
With gcc it fails to compile with error:
test.cpp:9:6: error: ‘Bar’ has not been declared
void Bar::baz() {}
^
To compile you either need:
void foo::Bar::baz() {}
Or enclose it inside namespace too.

C++ Immutability of classes and pros/cons

There are three ways I know of to create an immutable object.
Method 1: internally immutable class members, internally and externally unmodifiable.
#ifndef INTERNALLY_IMMUTABLE_HPP
#define INTERNALLY_IMMUTABLE_HPP
#include <string>
class internally_immutable
{
public:
internally_immutable(const std::string & str)
: str_(str)
{
}
std::string get_str() const
{
return str_;
}
private:
const std::string str_;
};
#endif
Method 2: externally immutable class members, externally unmodifiable.
#ifndef EXTERNALLY_IMMUTABLE_HPP
#define EXTERNALLY_IMMUTABLE_HPP
#include <string>
#include <vector>
class externally_immutable
{
public:
externally_immutable(const std::string & str)
: str_(str)
{
}
std::string get_str() const
{
return str_;
}
private:
std::string str_;
};
#endif
Method 3: type immutable, partially externally unmodifiable, as someone could bypass your typedef.
#ifndef TYPED_IMMUTABLE_HPP
#define TYPED_IMMUTABLE_HPP
#include <string>
#include <vector>
typedef const typed_mutable typed_immutable;
class typed_mutable
{
public:
typed_mutable(const std::string & str)
: str_(str),
vec_()
{
}
void set_str(const std::string & str)
{
str_ = str;
}
std::string get_str() const
{
return str_;
}
private:
std::string str_;
};
#endif
What are the pros and cons of each immutable type? Compiler optimizations, impediments, usage of each type... Are there other ways of creating immutable objects in C++? What is the recommended, or most common way to create these immutable classes in C++?
you can make the immutable class when will you make your constructor private in this case your derived class can't access base class.
like as .
class externally_immutable
{
private :
externally_immutable(const std::string & str)
: str_(str){}
// to do
const string str_;
};

How do I define a datatype to be an int in a structure without redefining my class type in a class object?

I am having difficulty resolving a redefinition error. Basically, I have a class object called houseClassType in my class header file and I also have to use houseClassType as my datatype for an array within my structure in my struct header file. Below are the two header files:
house header file:
#include "Standards.h"
#ifndef house_h
#define house_h
//Definition of class, house
class houseClassType
{
//Data declaration section
private:
int capacityOfGarage;
int yearBuilt;
int listingNumber;
double price;
double taxes;
double roomCounts[3];
string location;
string style;
//Private method to set the county name
string SetCountyName(string);
string SetSchoolDistrictName(string);
//Private method to set school district name
void SetSchoolDistrictName(void);
//Set function for the object
void ExtractLocationData(string& state, string& county, string& city,
string& schoolDistrictName, string& address);
//Methods declaration
public:
///Default Constructor
houseClassType(void);
///Get methods for data members - INLINE
int GetCapacity(void) { return capacityOfGarage; };
int GetYearBuilt(void) { return yearBuilt; };
int GetListingNumber(void) { return listingNumber; };
double GetPrice(void) { return price; };
double GetTaxes(void) { return taxes; };
string GetLocation(void) { return location; };
string GetStyle(void) { return style; };
void GetRoomCounts(double[]);
//Set methods for data members
void SetCapacityOfGarage(int);
void SetYearBuilt(int);
void SetListingNumber(int);
void SetPrice(double);
void SetTaxes(double);
void SetLocation(string);
void SetStyle(string);
void SetRoomCounts(double[]);
//Output methods for data members
void OutputLocationData(ofstream&);
void OutputStyle(ofstream&);
void OutputRoomCounts(ofstream&);
void OutputCapacityOfGarage(ofstream&);
void OutputYearBuilt(ofstream&);
void OutputPrice(ofstream&);
void OutputTaxes(ofstream&);
void OutputListingNumber(ofstream&);
void OutputHouse(ofstream&);
///Destructor
~houseClassType(void);
};
#endif
Realtor header file:
#include "Standards.h"
#ifndef Realtor_h
#define Realtor_h
const int NUMBER_OF_HOMES = 30;
typedef int houseClassType;
struct realtorStructType
{
string agentName;
houseClassType homes[NUMBER_OF_HOMES]; ///Redefinition error here
int numberOfHomes;
};
void InputHomes(ifstream& fin, string agentName, int& numberOfHomes);
#endif
Any help would be much appreciated.
The C++ language likes to have unique type names throughout a translation module. The following are not unique type names:
class houseClassType
typedef int houseClassType;
If you must use the same name, then you'll need to use namespaces to separate them:
namespace City
{
class houseClassType;
}
namespace Suburban
{
typedef int houseClassType;
}
struct realtorStructType
{
Suburban::houseClassType homes[MAX_HOMES];
};
I highly recommend you draw or design this issue first. This will help you with names too.
The simple solution is to use different names.
Also, do you need the suffix "ClassType" or "StructType" in your name? In a good design, whether it be a struct or class doesn't matter.
Your code is ambiguous. If you have
class houseClassType;
typedef int houseClassType;
What would the following code mean?
houseClassType x = new houseClassType();
You can resolve the ambiguity using a namespace, but it's better to change your second houseClassType type and name.
An example might look like this.
class House {
public:
enum class Type {
...
}
};

Static methods on boostcentric factory implementation

I'm trying to implement a C++ factory class that also perform the self registration of some derived classes. My implementation is based on the library:
http://arcticinteractive.com/2008/10/06/boost-centric-factory-pattern-implementation/
that is based on the Boost library. Just to give you a quick overview of this library, here is a simple self-explained (I hope) example:
struct foo { virtual ~foo() {} };
struct bar : foo { bar(int i) { std::cout << "bar() " << i << "\n"; } };
struct baz : foo { baz(int i) { std::cout << "baz() " << i << "\n"; } };
...
typedef factory< foo*(int) > myfactory_t;
myfactory_t f;
// Register a default (operator new) creator function
// for an implementation type
register_new_ptr<bar>(f, "bar");
register_new_ptr<baz>(f, "baz");
// Create objects through the factory
foo* fooimpl1 = f["bar"](1234);
foo* fooimpl2 = f["baz"](4321);
What I'm trying to do is to delegate each class to self-register them self to the factory using a static method. Here is the code:
animal.h
#pragma once
#include <cstring>
#include <iostream>
#include "factory.hpp"
#include "abstract_factory.hpp"
class zoo;
using namespace std;
using namespace boost::factory;
class animal{
virtual const std::string do_sound() const = 0;
std::string name_;
int age_;
zoo* myZoo_;
public:
animal(const std::string& name, int age, zoo* myZoo) : name_(name), age_(age), myZoo_(myZoo)
{}
virtual ~animal() {}
const std::string sound() const
{
return do_sound();
}
const std::string& name() const { return name_; }
const int age() const { return age_; }
};
template <class T>
struct animalFactory{
typedef factory< animal*(std::string&, int, zoo*) > myfactory_t;
static const myfactory_t* f;
static bool registerAnimal(const std::string& animalname){
return register_new_ptr<T>(&f, animalname);
};
};
When I try to register a class like:
crocodile.cpp
#include "crocodile.h"
bool r = animalFactory<crocodile>::registerAnimal("crocodile");
I get an error from visual studio 2012 that is:
animal.h(41): error C2893: Failed to specialize function template 'bool boost::factory::register_new_ptr(Factory &,Factory::id_param_type)'
Could someone help me to understand what is going on here? Thanks a lot!