How to call a Java function in JNI with custom class type argument - java-native-interface

I'm trying to call a Java function from C++ with a custom class type argument. The issue is that the Java function gets garbage values when called from C++ (code shown below). If I use the argument of any other data type (String, float, int) the same function printClassVar works correctly.
This is the Java code
/*Filename: CallbacksExample.java*/
public class CallbacksExample {
static {
System.loadLibrary("myjni");
}
public static void main(String[] args) {
new CallbacksExample().callback();
}
public native void callback();
public static void printClassVar(Person person)
{
System.out.println("Got callback from C++: " + person.age );
}
}
/*Filename: Person.java*/
public class Person {
public int age;
public Person() {
this.age = 20;
}
public int value() {
return age;
}
}
And here is the JNI code
/*Filename: CallbacksExample.cpp*/
#include <iostream>
#include <jni.h>
#include "CallbacksExample.h"
using namespace std;
class Person
{
int age;
public:
Person()
{
age = 5;
}
int value()
{
return age;
}
};
JNIEXPORT void JNICALL
Java_CallbacksExample_callback(JNIEnv *env, jobject jthis)
{
jclass thisClass = env->GetObjectClass(jthis);
Person _per;
Person* class_ptr = &_per;
std::cout << class_ptr->value() << std::endl;
jmethodID printClassVar = env->GetStaticMethodID(thisClass, "printClassVar", "(LPerson;)V");
if (NULL == printClassVar)
return;
env->CallVoidMethod(jthis, printClassVar, &class_ptr);
}
The above code returns
Got callback from C++: 1679598160 (Or any garbage signed int value)

Here is the proper way to call a Java function with class type argument in C++
/*Filename: CallbacksExample.java*/
public class CallbacksExample {
static {
System.loadLibrary("myjni");
}
public static void main(String[] args) {
new CallbacksExample().callback();
}
public native void callback();
public static void printClassVar(Person person)
{
System.out.println("Got callback from C++: " + person.age );
}
}
/*Filename: Person.java*/
public class Person {
public int age;
public Person() {
this.age = 20;
}
public void set(int x)
{
age = x;
}
public int value() {
return age;
}
}
/*Filename: CallbacksExample.cpp*/
#include <iostream>
#include <jni.h>
#include "CallbacksExample.h"
JNIEXPORT void JNICALL
Java_CallbacksExample_callback(JNIEnv *env, jobject jthis)
{
jclass thisClass = env->GetObjectClass(jthis);
jclass personClass = env->FindClass("Person");
jmethodID class_constructor = env->GetMethodID(personClass, "<init>", "()V"); // no parameters
jobject personObj = env->NewObject(personClass, class_constructor);
auto personMethod = env->GetMethodID(personClass, "set", "(I)V");
env->CallVoidMethod(personObj, personMethod, 15);
jmethodID printClassVar = env->GetStaticMethodID(thisClass, "printClassVar", "(LPerson;)V");
if (NULL == printClassVar)
return;
env->CallVoidMethod(jthis, printClassVar, personObj);
}

Related

How to Get Static Var Inside Class

I am new for C++, I want to do some thing like the Java language below without create an object, how do I do that?
public class ClassA {
**public static final NAME = "ClassA";**
}
public class Main {
public static void main(String[] args) {
System.out.println(**ClassA.NAME**);
}
}
C++98
class ClassA {
public:
static const std::string Name;
};
const std::string ClassA::Name = "ClassA";
int main()
{
std::cout << ClassA::Name << std::endl;
}
C++17
class ClassA {
public:
static inline const std::string Name = "ClassA";
};
int main()
{
std::cout << ClassA::Name << std::endl;
}
C++20
(cannot test it yet)
class ClassA {
public:
static constexpr std::string Name = "ClassA";
}
int main()
{
std::cout << ClassA::Name << std::endl;
}
#include <iostream>
#include <string>
static const std::string NAME = "ClassA";
int main()
{
std::cout << NAME;
}

Accessing list of fields and types in a class in c++

Hi i am trying to create a simple ORM in c++ for a project. For this example assuming a simple class as
class userProfile: public BaseOrm
{
public:
string username;
string email;
};
Now base orm has a method save() and migrate(). What i want is when a person calls migrate() all the schema , in this case username and email are populated as db tables and on save they persist on database.
What i am having problem with is how do i get what all fields are defined in the class, like in this example username and email and also there types, string in this case. Any help would be appreciated.
I know there is no reflection in c++, so i don't actually care about the variable name but more on the number of variables and there types to map them with DB.
adding reflection to c++ is not insanely difficult but it does require a reasonably good knowledge of template type deduction and some careful planning.
In this working example I have made a start for you. This framework supports writing the members out to a "statement" class (modelling a database prepared statement).
Similar techniques can be used to build out the SQL generation for CRUD.
No doubt there are already libraries that do this for you...
#include <iostream>
#include <iomanip>
#include <string>
#include <tuple>
#include <utility>
using namespace std;
struct statement
{
void setString(int index, const std::string& value)
{
std::cout << "setting index " << index << " to value " << std::quoted(value) << std::endl;
}
};
struct BaseOrm
{
virtual void serialise(statement& stmt) const = 0;
};
template<class Class>
struct class_tag {
using type = Class;
};
template<const char* Name>
struct name_tag {
static constexpr const char* name() { return Name; }
};
namespace detail {
struct reflection_item_concept
{
virtual const std::string& name() const = 0;
virtual std::string to_archive_string(const void* object) const = 0;
virtual void from_archive_string(void* object, const std::string& as) const = 0;
};
template<class T>
std::string to_archive_string_impl(const T& val) {
return std::to_string(val);
}
const std::string& to_archive_string_impl(const std::string& s) {
return s;
}
template<class NameTag, class Class, class Type>
struct reflection_item : reflection_item_concept
{
reflection_item(Type Class::* mfp) : mfp(mfp) {}
static const class_tag<Class> class_info() { return {}; };
static const char* raw_name() { return NameTag::name(); };
// concept implementation
const std::string& name() const override {
static const std::string s = raw_name();
return s;
}
std::string to_archive_string(const void* object) const override
{
auto& val = (*reinterpret_cast<const Class*>(object)).*mfp;
return to_archive_string_impl(val);
}
void from_archive_string(void* item, const std::string& as) const override
{
// similar mechanism here
}
Type Class::* mfp;
};
}
template<class NameTag, class Class, class Type>
constexpr auto reflection_item(NameTag, Type Class::* mp)
{
return detail::reflection_item<NameTag, Class, Type> { mp };
}
struct class_reflection_concept
{
virtual void serialise(const void* object, statement& stmt) const = 0;
};
namespace detail {
template<class ClassTag, class...ReflectionItems>
struct reflection_impl : class_reflection_concept
{
reflection_impl(ReflectionItems...refs)
: _reflectors(std::make_tuple(refs...))
{}
template<std::size_t...Is>
void serialise_impl(std::index_sequence<Is...>, const void* object,
statement& stmt) const
{
using expand = int[];
void(expand{
0,
(stmt.setString(Is + 1, std::get<Is>(_reflectors).to_archive_string(object)),0)...
});
}
void serialise(const void* object, statement& stmt) const override
{
serialise_impl(std::make_index_sequence<sizeof...(ReflectionItems)>(),
object, stmt);
}
std::tuple<ReflectionItems...> _reflectors;
};
}
template<class ClassTag, class...ReflectionItems>
auto& make_reflection(ClassTag tag, ReflectionItems...items)
{
static const detail::reflection_impl<ClassTag, ReflectionItems...> _ { items... };
return _;
}
const char txt_username[] = "username";
const char txt_email[] = "email";
const char txt_x[] = "x";
class userProfile: public BaseOrm
{
public:
string username = "test username";
string email = "noone#nowhere.com";
int x = 10;
// implement serialisation
void serialise(statement& stmt) const override
{
reflection.serialise(this, stmt);
}
static const class_reflection_concept& reflection;
};
const class_reflection_concept& userProfile::reflection =
make_reflection(class_tag<userProfile>(),
reflection_item(name_tag<txt_username>(), &userProfile::username),
reflection_item(name_tag<txt_email>(), &userProfile::email),
reflection_item(name_tag<txt_x>(), &userProfile::x));
int main()
{
userProfile x;
statement stmt;
x.serialise(stmt);
}
expected results:
setting index 1 to value "test username"
setting index 2 to value "noone#nowhere.com"
setting index 3 to value "10"
What I understand is that you want a generic behaviour for classes which have a variable set of fields.
I suggest you to create a "field" interface which will be stored in your base class with a container (for example a map of [fieldName, fieldInterface]). You still have to implement a behaviour for each field's type, but then you can create any class derived from the base class which have a dynamic set of field.
Here is an example :
#include <iostream>
#include <map>
using namespace std;
//the "Field" interface
class IFieldOrm
{
public:
virtual ~IFieldOrm() {}
virtual void save() = 0;
virtual void migrate() = 0;
};
//your base class
class BaseOrm
{
public:
virtual ~BaseOrm();
virtual void save();
virtual void migrate();
protected:
map<string, IFieldOrm*> m_fields; //prefer a smart pointer if you don't want to mess with raw pointer
};
//base class implementation
void BaseOrm::save()
{
for(auto& f : m_fields)
f.second->save();
}
void BaseOrm::migrate()
{
for(auto& f : m_fields)
f.second->migrate();
}
//don't forget to free your "fields" pointers if you have raw pointers
BaseOrm::~BaseOrm()
{
for(auto& f : m_fields)
delete f.second;
}
//then implement your basic types
//(like string, int, ..., whatever type you want to store in your database)
class StringFieldOrm : public IFieldOrm
{
public:
StringFieldOrm(const string& value) : m_value(value) {}
virtual void save();
virtual void migrate();
private:
string m_value;
};
void StringFieldOrm::save()
{
cout << "Save value " << m_value << endl;
//save stuff...
}
void StringFieldOrm::migrate()
{
cout << "Migrate value " << m_value << endl;
//migrate stuff...
}
class IntFieldOrm : public IFieldOrm
{
public:
IntFieldOrm(int& value) : m_value(value) {}
virtual void save();
virtual void migrate();
private:
int m_value;
};
void IntFieldOrm::save()
{
cout << "Save value " << m_value << endl;
//save stuff...
}
void IntFieldOrm::migrate()
{
cout << "Migrate value " << m_value << endl;
//migrate stuff
}
//and finally implement your final class
//note that this object can be "dynamically extended" by inserting new fields,
//you may want to prevent that and I can think of a solution if you want to
class UserProfile: public BaseOrm
{
public:
UserProfile(const string& username, const string& email, int age);
};
UserProfile::UserProfile(const string& username, const string& email, int age)
{
m_fields["username"] = new StringFieldOrm(username);
m_fields["email"] = new StringFieldOrm(email);
m_fields["age"] = new IntFieldOrm(age);
}
int main(int argc, char* argv[])
{
UserProfile user = UserProfile("Batman", "bw#batmail.com", 30);
user.save();
return 0;
}
create a userProfile variable and access them:
userProfile user;
int main(){
std::cout << user.username;
std::cout << user.email ;
}
this is how you would access them, except for different reasons, not printing them to the screen.

How to create an inline implementation of an abstract class? [duplicate]

This question already has answers here:
Is it possible to give a definition of a class in C++ during allocation, as is allowed in java
(4 answers)
Closed 6 years ago.
Let's say I have the following callback class:
class LogCallback {
public:
virtual void sendLog(std::string log) = 0;
virtual void setErrorCode(int code) = 0;
};
And I have the engine which accepts a callback implementation:
class Engine {
public:
Engine();
virtual ~Engine();
void setCallback(LogCallback* callback);
void start();
private:
LogCallback* logCallback;
};
Now I can create an implementation class:
class OutLogger : public LogCallback {
void sendLog(std::string log) {
cout << "out: " << log << endl;
}
void setErrorCode(int code) {
sendLog("error code " + std::to_string(code));
}
};
And use it:
int process() {
Engine engine;
OutLogger out;
engine.setCallback(&out);
engine.start();
}
In C++11 I can also use an anonymous local class:
int anonymous() {
Engine engine;
class : public LogCallback {
void sendLog(std::string log) {
cerr << "err: " << log << endl;
}
void setErrorCode(int code) {
sendLog("error code " + std::to_string(code));
}
} err;
engine.setCallback(&err);
engine.start();
}
Now there is the question: can I do the same without the explicit anonymous class, inside the function call?
If it was Java I would do it like this:
public class AnonymousClass {
private abstract class LogCallback {
abstract void sendLog(String log);
abstract void setErrorCode(int code);
}
private class Engine {
public void setCallback(LogCallback callback) {
this.callback = callback;
}
public void start() {
if (callback != null) {
callback.sendLog("Starting...");
}
}
private LogCallback callback;
}
public void process() {
Engine engine = new Engine();
engine.setCallback(new LogCallback() {
#Override
void sendLog(String log) {
System.out.println("out: " + log);
}
#Override
void setErrorCode(int code) {
sendLog("error code " + code);
}
});
engine.start();
}
public static void main(String[] args) {
AnonymousClass example = new AnonymousClass();
example.process();
}
}
Holt's comment above is correct. The only way to declare a new type in an expression like Java's new X() { ... } is a lambda expression, and you can't make that derive from your abstract base class.
The C++ way to do it would be to stop all that OOP inheritance ickiness and use a function template, or a function taking a type erased std::function, so it accepts any callable with a suitable call signature, then you could use a lambda.
For example:
class Engine {
public:
enum class LogType { String, ErrorCode };
using LogCallback = std::function<void(LogType, std::string, int)>;
Engine();
virtual ~Engine();
void setCallback(LogCallback callback) { logCallback = callback; }
void start() {
if (logCallback)
logCallback(LogType::String, "Starting...", 0);
}
private:
LogCallback logCallback;
};
int anonymous() {
Engine engine;
engine.setCallback([](Engine::LogType t, std::string log, int code) {
if (t == Engine::LogType::ErrorCode)
log = "error code " + std::to_string(code);
cerr << "err: " << log << endl;
});
engine.start();
}
(A nicer definition for the LogCallback type would be:
using LogCallback = std::function<void(std::variant<std::string, int>)>;
but we don't have variant in C++ just yet.)
You cannot implement interface in place, but you can create generic class with call back functions as parameters:
class GenericLogCallback : public LogCallback {
public:
GenericLogCallback(std::function<void (std::string)> sendlog,
std::function<void (int)> seterrorcode) : sendLog_(std::move(sendlog)),
setErrorCode_(std::move(seterrorcode)) {}
virtual void sendLog(std::string log) override {
if(sendLog_) sendLog_(log);
}
virtual void setErrorCode(int code) override {
if(setErrorCode_) setErrorCode_(code);
}
private:
std::function<void (std::string)> sendLog_;
std::function<void (int)> setErrorCode_;
};
...
GenericLogCallback err([](std::string){},[](int){});
engine.setCallback(&err);
The answers already posted here using std::function are good, but if you care a lot about performance you can do one better by directly storing the functors (which could be results of std::bind(), or C-style function pointers, or lambdas):
template <typename SendLog, typename SetErrorCode>
class GenericLogger : public LogCallback {
public:
GenericLogger(SendLog sender, SetErrorCode setter)
: m_sender(sender), m_setter(setter) {}
void sendLog(std::string log) override {
m_sender(log);
}
void setErrorCode(int code) override {
m_setter(code);
}
SendLog m_sender;
SetErrorCode m_setter;
};
template <typename SendLog, typename SetErrorCode>
GenericLogger<SendLog, SetErrorCode> makeLogger(SendLog sender, SetErrorCode setter) {
return GenericLogger<SendLog, SetErrorCode>(sender, setter);
}
void sendLog(std::string log) {
std::cout << "out: " << log << std::endl;
}
void setErrorCode(int code) {
sendLog("error code " + std::to_string(code));
}
int main()
{
Engine engine;
auto out = makeLogger(
[](std::string s){std::cout << "lambda: " << s << '\n';},
setErrorCode);
engine.setCallback(&out);
engine.start();
}
The above avoids using std::function except when the actual arguments to makeLogger() are of that type. This reduces overhead by invoking exactly the given functor, rather than always storing a std::function.
One thing you could do is create a wrapper class that allows to use lambdas:
template<class F1, class F2>
struct LogCallbackF : LogCallback {
F1 f1;
F2 f2;
LogCallbackF(F1 f1, F2 f2) : f1(std::move(f1)), f2(std::move(f2)) {}
void sendLog(std::string msg) override { f1(msg); }
void setErrorCode(int code) override { f2(code); }
};
template<class F1, class F2>
inline LogCallbackF<F1, F2> make_log_callback(F1 f1, F2 f2) {
return {std::move(f1), std::move(f2)};
}
void process() {
Engine engine;
auto callback = make_log_callback(
[](std::string a) { std::cout << a << '\n'; },
[](int a) { std::cout << a << '\n'; }
);
engine.setCallback(&callback);
engine.start();
}

How to create a specialized and default versions of a function that take base and derived classes?

I have the following class architecture:
class Animal
{
// ...
}
class Cat : public Animal
{
// ...
}
class Dog : public Animal
{
// ...
}
// + Several other derived classes
In another section of my code, I have a function that goes through a list of Animals and needs to perform specialized actions in the case of several of the derived classes and a default action otherwise. How can I handle this situation elegantly, given the following constraints:
I'd like to keep the new code outside of Animal and its derived
classes because of separation of concerns.
I'd like to avoid using a switch statement on types or enums as it feels very smelly.
Here's one way - use the concept-model idiom (my name):
#include <iostream>
#include <vector>
struct AnimalConcept {
virtual ~AnimalConcept() = default;
virtual void make_noise() const = 0;
};
// default case
void make_noise_for(const AnimalConcept&)
{
std::cout << "no noise" << std::endl;
}
template<class Model>
struct AnimalModel : AnimalConcept
{
void make_noise() const override {
make_noise_for(static_cast<const Model&>(*this));
}
};
// some models
struct Cat : AnimalModel<Cat>
{
};
struct Dog : AnimalModel<Dog>
{
};
struct Giraffe : AnimalModel<Giraffe>
{
};
// separation of concerns - specific overrides
void make_noise_for(const Cat&) {
std::cout << "meow\n";
}
void make_noise_for(const Dog&) {
std::cout << "woof\n";
}
// test
using namespace std;
int main(){
std::vector<std::unique_ptr<const AnimalConcept>> animals;
animals.emplace_back(new Cat);
animals.emplace_back(new Dog);
animals.emplace_back(new Giraffe);
for (const auto& p : animals) {
p->make_noise();
}
return 0;
}
expected output:
meow
woof
no noise
And here's another way to implement it (this one is nicer since it allows all animals to have unrelated interfaces):
#include <iostream>
#include <vector>
struct AnimalConcept {
virtual ~AnimalConcept() = default;
virtual void make_noise() const = 0;
};
// default case
template<class T>
void make_noise_for(const T&)
{
std::cout << "this animal makes no noise" << std::endl;
}
template<class Model>
struct AnimalModel : AnimalConcept
{
template<class...Args>
AnimalModel(Args&&...args)
: _model { std::forward<Args>(args)... }
{}
private:
void make_noise() const override {
make_noise_for(_model);
}
Model _model;
};
// some models
struct Cat
{
Cat(std::string name)
: _name { std::move(name) }
{}
const std::string& name() const {
return _name;
}
private:
std::string _name;
};
struct Dog
{
Dog(std::string name, int age)
: _name { std::move(name) }
, _age { age }
{}
const std::string& name() const {
return _name;
}
int age() const {
return _age;
}
private:
std::string _name;
int _age;
};
struct Giraffe
{
};
// separation of concerns - specific overrides
void make_noise_for(const Cat& c) {
std::cout << c.name() << " says meow\n";
}
void make_noise_for(const Dog& d) {
std::cout << "the dog called " << d.name() << " who is " << d.age() << " years old says woof\n";
}
// test
using namespace std;
int main(){
std::vector<std::unique_ptr<const AnimalConcept>> animals;
animals.emplace_back(new AnimalModel<Cat> { "felix" });
animals.emplace_back(new AnimalModel<Dog> { "fido", 2 });
animals.emplace_back(new AnimalModel<Giraffe>);
for (const auto& p : animals) {
p->make_noise();
}
return 0;
}
expected output:
felix says meow
the dog called fido who is 2 years old says woof
this animal makes no noise
You can use a combination of the following to get type based dispatch.
Provide for every class to return a type ID associated with it.
Provide a virtual function in the base class to get the type ID associated with an object.
Provide a way for registration of functions based on type ID.
When the time comes for execution of the top level function, search for a registered function given an animal's type ID. If a function is registered, call it. Otherwise, use the default function.
// Implement this function in a .cpp file.
int getNextTypeID()
{
static int typeID = 0;
return ++typeID;
}
class Animal
{
virtual int getTypeID();
};
class Cat : public Animal
{
static int getID()
{
static int typeID = getNextTypeID();
}
virtual int getTypeID()
{
return getID();
}
};
class Dog : public Animal
{
static int getID()
{
static int typeID = getNextTypeID();
}
virtual int getTypeID()
{
return getID();
}
};
foo.h:
typedef void (*AnimalFunction)(Animal& a);
int registerAnimalFunctor(int typeID, AnimalFunction f);
void foo(Animal& a);
foo.cpp:
typedef std::map<int, AnimalFunction> AnimalFunctionMap;
AnimalFunctionMap& getAnimalFunctionMap()
{
static AnimalFunctionMap theMap;
return theMap;
}
int registerAnimalFunctor(int typeID, AnimalFunction f)
{
getAnimalFunctionMap()[typeID] = f;
return 0;
}
void defaultAnimalFunction(a)
{
// Default action
}
void foo(Animal& a)
{
AnimalFunctionMap& theMap = getAnimalFunctionMap();
AnimalFunctionMap::iterator iter = theMap.find(a.getTypeID());
if ( iter != theMap.end() )
{
iter->second(a);
}
else
{
defaultAnimalFunction(a);
}
}
cat_foo.cpp:
void CatFunction(Animal& a)
{
// Cat action.
}
int dummy = registerAnimalFunctor(Cat::getID(), CatFunction);
dog_foo.cpp:
void DogFunction(Animal& a)
{
// Dog action.
}
int dummy = registerAnimalFunctor(Dog::getID(), DogFunction);

Incomplete type --> Can't Access Pointer value from my object

I'm trying to access one of my pointers within my class, however I can't seem to even get VS to acknowledge the pointer is there.
private:
ForwardTo* forward;
and here's how I grab it from the class
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
The ForwardTo type is an inherited class that typically reads:
class ForwardToTwo : public ForwardTo
{
public:
ForwardToTwo(unsigned int strategy);
virtual std::vector<std::string> forwardMessage(Persons& person, Message& message);
unsigned int getStrategy() const { return strategy;};
private:
unsigned int strategy;
};
and finally, here's how I'm trying to access the pointer
listOfPersons.at(i).getForwardTo()->forwardMessage(listOfPersons.at(i), tempMessage);
This style of access worked previously for my OTHER pointer in my class that acts exactly this same as this one.
While typing the line to access the pointer out in VS, intelliSense picks up all the functions up to getForwardTo(), and after that, the dot operator/arrow operator don't bring up any access to functions.
Thanks again for all help.
(edit, I'm aware the function fordwardMessage() function will return a vector, I was just typing in the VS until intelliSense failed to detect the accessible functions)
(edit 2, I've tried both the . operator and the -> operator, yet neither allow intelliSense to detect any functions.)
(edit 3, additional code:
Here is my Persons Class Header:
#ifndef PERSONS_HPP
#define PERSONS_HPP
#include <string>
#include <vector>
#include <list>
#include <map>
#include "Message.hpp"
#include "TypeOne.hpp"
#include "TypeTwo.hpp"
#include "TypeThree.hpp"
#include "TypeFour.hpp"
#include "TypeFive.hpp"
class ForwardTo;
class ForwardToOne;
class ForwardToTwo;
class ForwardToThree;
class Persons
{
public:
Persons();
~Persons();
void setEmailAddress(std::string email);
std::string getEmailAddress() const;
const std::vector<std::string>& getContactList() const;
void addMessageSeen(Message message);
void addMessageContent(MessageContent mc);
void addInboxMessage(Message message);
void addContact(std::string contact);
void viewContact(const std::vector<std::string>& contacts);
void bumpContact();
void setMessageTypeOne();
void setMessageTypeTwo(unsigned int type);
void setMessageTypeThree(unsigned int quality);
void setMessageTypeFour(unsigned int type, unsigned int quality);
void setMessageTypeFive();
void setForwardTypeOne(unsigned int strategy);
void setForwardTypeTwo(unsigned int strategy);
void setForwardTypeThree(unsigned int strategy);
void printPersonsObj();
std::list<Message> getInbox() const;
MessageType& getForwardWhen() const;
ForwardTo& getForwardTo() const;
private:
std::map<MessageContent, unsigned int> messageList;
std::list<Message> inbox;
std::vector<std::string> contactList;
std::string emailAddress;
ForwardTo* forward;
MessageType* forwardWhen;
};
And here is my Persons.cpp file is:
#include "Persons.hpp"
#include "ForwardToOne.hpp"
#include "ForwardToTwo.hpp"
#include "ForwardToThree.hpp"
#include <iostream>
Persons::Persons()
:emailAddress(""), contactList(), inbox(), messageList()
{
}
Persons::~Persons()
{
//delete forwardWhen;
//delete forwardTo;
}
void Persons::addMessageContent(MessageContent mc)
{
//messageSeen.insert(mc);
}
void Persons::setEmailAddress(std::string email)
{
emailAddress = email;
}
std::string Persons::getEmailAddress() const
{
return emailAddress;
}
void Persons::addContact(std::string contact)
{
contactList.push_back(contact);
}
void Persons::addInboxMessage(Message message)
{
inbox.push_back(message);
}
void Persons::viewContact(const std::vector<std::string>& contacts)
{
for(auto i = contacts.begin(); i != contacts.end(); i ++)
{
std::cout << *i << std::endl;;
}
}
void Persons::setMessageTypeOne()
{
MessageType* forwardWhen = new TypeOne();
}
void Persons::setMessageTypeTwo(unsigned int type)
{
MessageType* forwardWhen = new TypeTwo(type);
}
void Persons::setMessageTypeThree(unsigned int quality)
{
MessageType* forwardWhen = new TypeThree(quality);
}
void Persons::setMessageTypeFour(unsigned int type, unsigned int quality)
{
MessageType* forwardWhen = new TypeFour(type, quality);
}
void Persons::setMessageTypeFive()
{
MessageType* forwardWhen = new TypeFive();
}
void Persons::setForwardTypeOne(unsigned int strategy)
{
ForwardTo* forward = new ForwardToOne(strategy);
}
void Persons::setForwardTypeTwo(unsigned int strategy)
{
ForwardTo* forward = new ForwardToTwo(strategy);
}
void Persons::setForwardTypeThree(unsigned int strategy)
{
ForwardTo* forward = new ForwardToThree(strategy);
}
const std::vector<std::string>& Persons::getContactList() const
{
return contactList;
}
void Persons::bumpContact()
{
std::vector<std::string> tempList = getContactList();
std::string tempContact = tempList.at(0);
for(unsigned int i = 0; i <= tempList.size(); i ++)
{
if(i == tempList.size())
tempList.at(--i) = tempContact;
else
tempList.at(--i) = tempList.at(i);
}
}
void Persons::addMessageSeen(Message message)
{
messageList[*message.getMessageContent()] = message.getMessageContent()->getUniqueID();
}
void Persons::printPersonsObj()
{
std::cout << "PERSONS OBJECT!" << std::endl;
std::cout << "E-mail Address: " << emailAddress << std::endl;
std::cout << std::endl;
}
std::list<Message> Persons::getInbox() const
{
return inbox;
}
MessageType& Persons::getForwardWhen() const
{
return *forwardWhen;
}
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
Incomplete type normally means that at the point at which you are trying to use getForwardTo, you have not fully declared the ForwardTo class. Indeed in your persons.hop there is only a forward declaration.
Make sure you have included the header that fully declares ForwardTo in the file containing the call site.
getForwardTo() returns a T&, just use the . to access forwardMessage()