Return the name of object in method - c++

I'm pretty new to coding, and I'm following this French tutorial that is basically making a RPG game used through console.
So I got a Character class in a .cpp file and .h, another .h .cpp couple of files for the weapons, and my main.
I got a function on my CPP file that's like this :
void Character::attack(Character &target)
{
target.takeDamage(m_weapon.getDamage());
}
So far, in understand I'll use it in this way : davids.attack(goliath) and I made an alias so I can easily use the takeDamage function of my target using its alias.
but I'd like to add a console line like David attacked Goliath and made X damages in that function.
And it looks like I can't call another function like
string Character::getname
{return name}
due to the fact I use 2 different characters.
Is there a way to get around that or should I get them both an alias?

Assuming the Character class has field like name you can access the field in your method by using this->name (it will acces name of the object which called the method, in this case it is David) and the target.name will be "Goliath".

If C++17 is available to you I recommend using CRTP.
#include <iostream>
#include <string>
#include <string_view>
template <typename Derived>
class Character{
static constexpr std::string_view CName = "Character";
public:
constexpr const std::string_view& getName() { return Derived::CName; }
template<typename K>
void Attack(Character<K>& Target) {
std::cout << getName() << " attacked " << Target.getName() << "\n";
}
};
class David : public Character<David>{
public:
static constexpr std::string_view CName = "David";
};
class Goliath : public Character<Goliath>{
public:
static constexpr std::string_view CName = "Goliath";
};
int main(int a, char** argv){
David d;
Goliath g;
d.Attack(g);
return 0;
}
Output:

Related

Seperating C++ Nested Classes into their Own Header Files

new to this site and also C++ but hoping to see some guidance from everyone.
I had a pretty fun project idea to learn C++ digging deeper with APIs, classes, references, etc. and currently I have a working example of code where everything exist within the main.cpp file. The issue I am facing is that when i move the classes (inner and outer) to their own respective header files the code no longer compiles.
The reason for the nested classes is that the OuterAPI serves as the main entry point to the API and has many lower level APIs that can be then accessed beneath it (people, licenes, roles, etc). This way users of API would only have to create an object for the OuterAPI and then dot notation for underlying resource and method.
Here is the working example in the main.cpp
#include <iostream>
#include <nlohmann/json.hpp>
#include <cpr/cpr.h>
using json = nlohmann::json;
class OuterAPI {
private:
class InnerAPI {
private:
OuterAPI& api;
public:
InnerAPI(OuterAPI& a) :api(a) {}
json get() {
cpr::Response r = cpr::Get(
cpr::Url{ api.baseUrl + "resource" },
cpr::Bearer{ api.token }
);
return json::parse(r.text)
};
std::string token;
std::string baseUrl = "";
public:
InnerAPI people;
OuterAPI(std::string t) : token(t), people(*this) {}
};
int main(int argc, char** argv)
{
std::string token = "";
OuterAPI api(token);
json jsonData = api.people.get();
std::cout << jsonData.dump(4) << std::endl;
return 0;
}
Here is me moving everything to respective header/cpp files
OuterAPI.h
#pragma once
class OuterAPI {
private:
class InnerAPI;
std::string token;
std::string baseUrl = "";
public:
OuterAPI(std::string t);
~OuterAPI();
InnerAPI* people;
};
OuterAPI.cpp
#include "WebexAPI.h"
#include "PeopleAPI.h"
OuterAPI::OuterAPI(std::string t) : token(t) {
people = new InnerAPI(*this);
}
OuterAPI::~OuterAPI() { delete people; }
InnerAPI.h
#pragma once
#include <nlohmann/json.hpp>
#include <cpr/cpr.h>
#include "OuterAPI.h"
using json = nlohmann::json;
class OuterAPI::InnerAPI {
private:
OuterAPI& api;
public:
InnerAPI(OuterAPI& a);
json get();
};
InnerAPI.cpp
#include "InnerAPI.h"
OuterAPI::InnerAPI::InnerAPI(OuterAPI& a) : api(a) {}
json OuterAPI::InnerAPI::get() {
cpr::Response r = cpr::Get(
cpr::Url{ api.baseUrl + "resource" },
cpr::Bearer{ api.token }
);
return json::parse(r.text);
main.cpp (finally) - this is where the compiler error occurs at api.people.get() "expression must have class type but has type "OuterAPI::InnerAPI *"
int main(int argc, char** argv)
{
std::string token = "";
OuterAPI api(token);
json jsonData = api.people.get(); // COMPILER ERROR "expression must have class type but has type "OuterAPI::InnerAPI *"
std::cout << jsonData.dump(4) << std::endl;
return 0;
}
From this I believe the issue is associated with me having to define the InnerAPI object people as a pointer inside of OuterAPI but from here I cant seem to come to a resolution.
Also, feel free to critique my design as well, like I say I am new to C++ so want to make sure I can do a good job. Thanks.
In OuterAPI* you have declared people as a member of type InnerAPI*.
You can either call your API using api.people->get() or make the member a InnerAPI instead.
EDIT:
It seems the error, besides the pointer thing, comes from how you handle file includes. I managed to get a working version on REPL.it. I made slight adjustments so I wouldn't have to bring both libraries in so focus on the gist of it. Here it is:
OuterAPI.h
#pragma once
#include <string>
class OuterAPI {
private:
class InnerAPI;
std::string token;
std::string baseUrl = "";
public:
OuterAPI(std::string t);
~OuterAPI();
InnerAPI* people;
};
InnerAPI.j
#pragma once
#include "./OuterAPI.h"
class OuterAPI::InnerAPI {
private:
OuterAPI& api;
public:
InnerAPI(OuterAPI& a);
std::string get();
};
OuterAPI.cpp
#include "./OuterAPI.h"
#include "./InnerAPI.h"
OuterAPI::OuterAPI(std::string t) : token(t) {
people = new InnerAPI(*this);
}
OuterAPI::~OuterAPI() { delete people; }
InnerAPI.cpp
#include "./OuterAPI.h"
#include "./InnerAPI.h"
OuterAPI::InnerAPI::InnerAPI(OuterAPI& a) : api(a) {}
std::string OuterAPI::InnerAPI::get() {
return api.baseUrl + "resource";
}
Make sure you include everything you intend to use in every file where you intend to do so.
Separating declaration and definition is pretty common.
It's a way to reduce compile time on large projects.
Thankfully modules will soon™ make linking a thing of the past.
To address the error message: you declare people as a raw member pointer of the class OuterAPI… You cannot access a member through a pointer using operator ., you need to use operator ->.

How to pretty print the name of a template parameter at compile time

The question is rather simple: how to pretty print the name of a template parameter in a C++ class and assign it to a class variable at compile time ?
It seems that both typeinfo (typeid) and boost::typeindex must be evaluated at runtime or as least some part of them. This apparently does not allow the compiler to completely solve a constexpr containing a call to one of this function.
template<typename T>
class X
{
public:
static const char * name = /* SOME C++ code transforming T in a string (either std::string or char */
};
What am I missing ?
Is it only possible to generate a name at runtime ? In that case, does I really need an instantiated object ? It doesn't seem right to me, because the following perfectly work without any instance:
#include <iostream>
#include <string>
#include <boost/type_index.hpp>
using namespace std;
template<class T>
class X
{
public:
static std::string name()
{
return boost::typeindex::type_id<T>().pretty_name();
}
};
struct foobar {};
int main()
{
cout << X<int>::name() << endl;
cout << X<foobar>::name()<< endl;
}
So instead of having name() as a class method, I'd like to have it as a class variable.
I think, it is possible to use custom Type Traits. Please see the next example:
#include <iostream>
#include <string>
using namespace std;
//Using stub type traits
template <class T>
struct TypeTraits;
//your TypeTraits for specific types...
template<>
struct TypeTraits<int>
{
constexpr static const char *name = "int";
};
template<class T>
class X
{
public:
constexpr static const char * name = TypeTraits<T>::name;
};
struct foobar {};
//TypeTraits for custom foobar
template<>
struct TypeTraits<foobar>
{
constexpr static const char *name = "foobar";
};
int main()
{
//Now you can use static member here
cout << X<int>::name << endl;
cout << X<foobar>::name<< endl;
}
Also TypeTraits can be used (and expanded) for other purposes.

Casting to undeclared type

The idea is identical to the generic version of GetComponent() in Unity. But I'm currently stumbling on the following template issue:
template<class T> std::shared_ptr<T> MyClass::GetMyComponent()
{
for (int i = 0; i < _baseTypeList.size(); i++)
{
auto base = _baseTypeList[i];
T* check = dynamic_cast<T*>(base.get());
if (check)
{
return std::static_pointer_cast<T>(base);
}
}
return std::shared_ptr<T>(nullptr);
}
where _baseTypeList is a std::vector<std::shared_pntr{MyBaseType}> types.
In this function, I am iterating over a list of components to find if there is one that matches the type I'm asking for. if there is one, return the component cast to that type. Otherwise return a nullptr.
However, when I call this function from outside code, I get the following error:
error C2680: 'MyType*' : invalid target type for dynamic_cast
where MyType is some class that derives from component.
When I put #include "MyType.h" in the header it compiles just fine but without it it gives this error and doesn't compile.
This means I cannot use it in other classes without modifying the header file this template class resides in, which will be a problem for me.
Is there a way I can achieve simular results without having to #include every single header of the type I pass in the template for?
[EDIT]
For clarity, consider a person using my library, he creates a type
"Foo : MyBaseType" where MyBaseType has a virtual method "Update" that is called every frame.
any instance of class MyBaseType (including Foo) is to be managed by this library, and have update called every frame.
This library thus has a large list of "MyBaseType" objects. But has no knowledge of the actual type they are, just that they derive from "MyBaseType", so it can call Update() on them.
If I need a specific type the library needs to be able to search for it in this list and return it.
I would like this "search" to happen in the library itself, so I do not have to expose the list, and write a new "search" method for every type that derives from "MyBaseType"
[FINAL]
It turned out I messed up the include order in my project.
a minimal example of what I was trying to do would be:
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <memory>
#include "vector"
class MyBaseClass
{
virtual void Update(){};
};
class MyLibrary
{
public:
template<class T> std::shared_ptr<T> GetComponent();
std::vector<std::shared_ptr<MyBaseClass>> list;
};
template<class T> std::shared_ptr<T> MyLibrary::GetComponent()
{
static_assert(std::is_base_of<MyBaseClass, T>::value, "T1 is no subclass of ModelComponent");
for (unsigned int i = 0; i < list.size(); i++)
{
auto comp = list[i];
T* check = dynamic_cast<T*>(comp.get());
if (check)
{
return std::static_pointer_cast<T>(comp);
}
}
return std::shared_ptr<T>(nullptr);
}
class MyClass : public MyBaseClass
{
void Update() override;
};
void MyClass::Update()
{
}
int _tmain(int argc, _TCHAR* argv[])
{
MyLibrary lib;
lib.list.push_back(std::make_shared<MyClass>());
auto var = lib.GetComponent<MyClass>();
std::cout << (var ? "var is object" : "var is not") << std::endl;
while (true)
{
}
return 0;
}
which works as expected.
The primary issue was that the compiler gave an error in the "GetMyComponent" function, so I found a usage of it that did everything as suggested.
But it turned out there was a second usage that did not have the definition of "MyClass" before calling it (but didn't give an error, as it was forward declared in its header file).
You don't need the definition of possible T types included into your header. You do need the relevant one defined in the translation unit in which the template is expanded:
// client.cpp
#include <myclass.h>
#include <foo.h> // defines class Foo
void f(MyClass *p)
{
auto c = p->GetMyComponent<Foo>();
c->foobar();
}

C++ Initialization of static function pointer array

I want to create a static function pointer array, so I can jump to a certain function regarding a received index. Like an index jumper.
So imagine a class like this:
Class A
{
private:
static void 1stFunction();
static void 2ndFunction();
static void(*functionPointer[20])(void);
};
Then I would like that functionPointer to get the value of the 1stFunction and 2ndFunction, and maybe even more.
So, how do I initialize it?
As far as I know, when a static member is declared, you can use it even before an instance is created. So I though, lets initialize that function pointer, so later I can call it like this
functionPointer[receivedIndex]();
So i tried to initilize it like this, in the same .h file
void (*A::functionPointer[])(void) =
{
A::1stFunction,
A::2ndFunction,
};
But the compiler gives me redifinition, it says it's already created.
So, pretty sure I'm missing something. I don't know though, if it is syntax or simply it is not possible to do it this way.
I know that function pointers to class's member functions are different than normal function pointers... But this is a static function, so I believe it doesn't belong to an instance and therefore it should work with normal function pointers.
Any help would be appreciated.
Thanks
The following would be a working example that probably achieves what you need.
You need C++11 for the initializer list.
It is a good practice to initialize the static member in the cpp file, as you don't want to have a definition of the static member everytime the header is included (this can lead to linking issues).
You can call callf with the desired index and have the corresponding function called, based on the initialization of the function pointer array.
The output of the program would be:
I am 2ndFunction
Header file
class A
{
private:
static void Function1();
static void Function2();
static void(*functionPointer[20])();
public:
static void callf(int index);
};
Implementation
#include <iostream>
#include "ex.h"
void(*A::functionPointer[20])() {
A::Function1,
A::Function2
};
void A::Function1() {
std::cout << "I am 1stFunction" << std::endl;
}
void A::Function2() {
std::cout << "I am 2ndFunction" << std::endl;
}
void A::callf(int index) {
A::functionPointer[index]();
}
int main(int argc, char const *argv[]) {
A::callf(1);
return 0;
}
Here you have a more modern C++ approach (C++14 needed)
I would advise you to explore lambda functions if you are not restricted to C++03.
#include <iostream>
#include <functional>
#include <vector>
class A {
public:
using f_type = std::function<void(void)>;
f_type f1 = []() { std::cout << "f0" << std::endl;};
f_type f2 = []() { std::cout << "f1" << std::endl;};
static void f3() { std::cout << "f3" << std::endl; }
std::vector<f_type> functions{f1, f2, f3};
};
int main() {
A a;
a.functions[0]();
a.functions[1]();
//adding custom lambda
a.functions.emplace_back([](){ std::cout << "custom f" << std::endl;});
a.functions[2]();
return 0;
}
you can add both functions and lambdas to your container.

How to create a library that wraps an object with a template function using minimal includes?

The goal of this project is to create a library for distribution. In the past, I used forward declares so I didn't have to distribute a bunch of header files along with the libraries. However, I'm now trying to eliminate code duplication by switching to templates and am running into some issues.
First, a simple example project showing what is currently working:
//LibraryDep1.h
class LibraryDep1
{
public:
LibraryDep1(void) {};
virtual ~LibraryDep1(void) {};
template <typename T>
int TestFunction(T value)
{
std::cout << value << std::endl;
return 0;
}
};
//LibraryInclude.h
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
int TestFunction(int value);
int TestFunction(std::string value);
};
//LibraryInclude.cpp
#include "LibraryInclude.h"
#include "LibraryDep1.h"
LibraryInclude::LibraryInclude(void)
{
this->mLibDep1 = new LibraryDep1();
}
LibraryInclude::~LibraryInclude(void)
{
delete this->mLibDep1;
}
int LibraryInclude::TestFunction(int value)
{
return this->mLibDep1->TestFunction(value);
}
int LibraryInclude::TestFunction(std::string value)
{
return this->mLibDep1->TestFunction(value);
}
//main.cpp
#include <tchar.h>
#include "LibraryInclude.h"
int _tmain(int argc, _TCHAR* argv[])
{
LibraryInclude inclLibrary;
inclLibrary.TestFunction(77);
inclLibrary.TestFunction("test");
}
This gives the expected output of:
77
test
However, the overloads of LibraryInclude::TestFunction could be replaced with a template function to further reduce code duplication:
//LibraryInclude.h
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
template <typename T>
int TestFunction(T value) {
return mLibDep1->TestFunction(value);
}
};
The problem now is that I'm using mLibDep1 without including the full implementation giving me an undefined type compilation error. Meaning that I need to #include "LibraryDep1.h" in LibraryInclude.h, thus requiring me to distribute both LibraryInclude.h and LibraryDep1.h with my library. This is a simple example, the real project has many header files that would need to be distributed if I were to switch to using the templated version of LibraryInclude.
My question is, is there any way to avoid having to distribute a bunch of include files with my library and eliminate code duplication? Or, am I better off just overloading for all known types (drastically reducing library flexibility) in the distributed header file and keeping the templates in only the underlying classes?
No. There is currently no way to do what you want. When compiler vendors start implementing the 'export' keyword you'll be in luck. Currently I only know of Comeau doing so. This keyword has been around for years so I wouldn't hold my breath until the rest implement it.
A very limited and ugly solution would be:
//LibraryDep1.h
#pragma once
#include <iostream>
class LibraryDep1
{
public:
LibraryDep1(void) {};
virtual ~LibraryDep1(void) {};
template <typename T>
int TestFunction(T value)
{
std::cout << value << std::endl;
return 0;
}
};
//LibraryInclude.h
#pragma once
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
template <typename T>
int TestFunction(T value);
};
//LibraryInclude.cpp
#include "LibraryInclude.h"
#include "LibraryDep1.h"
#include <string>
LibraryInclude::LibraryInclude(void)
{
mLibDep1 = new LibraryDep1();
}
LibraryInclude::~LibraryInclude(void)
{
}
// only to save some typing when only forwaring calls
#define LI_TESTFUNCTION( TYPE ) \
template<> \
int LibraryInclude::TestFunction<TYPE>( TYPE value ) {\
return mLibDep1->TestFunction(value); \
}
// the allowed specializations, everything else causes link errors
LI_TESTFUNCTION( int );
LI_TESTFUNCTION( std::string );
Tested this with VC++ 2k8 & g++ 4.3.4 statically linking against LibraryInclude.o