I'm trying to implement a custom vtable to better understand a concept of virtual tables and overriding. For this I have the following 'base' class
#pragma once
#include <iostream>
#include <string>
using namespace std::string_view_literals;
struct vtable;
class IdentityDocument {
public:
IdentityDocument()
: vtable_ptr_(&IdentityDocument::VTABLE),
unique_id_(++unique_id_count_)
{
std::cout << "IdentityDocument::Ctor() : "sv << unique_id_ << std::endl;
}
~IdentityDocument() {
--unique_id_count_;
std::cout << "IdentityDocument::Dtor() : "sv << unique_id_ << std::endl;
}
IdentityDocument(const IdentityDocument& other)
: vtable_ptr_(other.vtable_ptr_),
unique_id_(++unique_id_count_)
{
std::cout << "IdentityDocument::CCtor() : "sv << unique_id_ << std::endl;
}
IdentityDocument& operator=(const IdentityDocument&) = delete;
void PrintID() const {
std::cout << "IdentityDocument::PrintID() : "sv << unique_id_ << std::endl;
}
static void PrintUniqueIDCount() {
std::cout << "unique_id_count_ : "sv << unique_id_count_ << std::endl;
}
int GetID() const {
return unique_id_;
}
private:
vtable* vtable_ptr_ = nullptr;
static int unique_id_count_;
static vtable VTABLE;
int unique_id_;
};
struct vtable
{
void (IdentityDocument::* const PrintID)() const;
vtable (
void (IdentityDocument::* const PrintID)() const
) : PrintID(PrintID) {}
};
int IdentityDocument::unique_id_count_ = 0;
vtable IdentityDocument::VTABLE = {&IdentityDocument::PrintID};
And here is another class that must override PrintId method
#pragma once
#include "identity_document.h"
#include <iostream>
#include <string>
#include <ctime>
using namespace std::string_view_literals;
class Passport {
public:
Passport()
: expiration_date_(GetExpirationDate())
{
IdentityDocument* base_ptr = reinterpret_cast<IdentityDocument*>(this);
vtable* vtable_ptr = reinterpret_cast<vtable*>(base_ptr);
vtable_ptr = &Passport::VTABLE;
std::cout << "Passport::Ctor()"sv << std::endl;
}
Passport(const Passport& other)
: identity_(other.identity_)
, expiration_date_(other.expiration_date_)
{
IdentityDocument* base_ptr = reinterpret_cast<IdentityDocument*>(this);
vtable* vtable_ptr = reinterpret_cast<vtable*>(base_ptr);
vtable_ptr = &Passport::VTABLE;
std::cout << "Passport::CCtor()"sv << std::endl;
}
~Passport() {
std::cout << "Passport::Dtor()"sv << std::endl;
}
void PrintID() const {
std::cout << "Passport::PrintID() : "sv << identity_.GetID();
std::cout << " expiration date : "sv << expiration_date_.tm_mday << "/"sv << expiration_date_.tm_mon << "/"sv
<< expiration_date_.tm_year + 1900 << std::endl;
}
void PrintVisa(const std::string& country) const {
std::cout << "Passport::PrintVisa("sv << country << ") : "sv << identity_.GetID() << std::endl;
}
private:
IdentityDocument identity_;
const struct tm expiration_date_;
static vtable VTABLE;
tm GetExpirationDate() {
time_t t = time(nullptr);
tm exp_date = *localtime(&t);
exp_date.tm_year += 10;
mktime(&exp_date);
return exp_date;
}
};
vtable Passport::VTABLE = {reinterpret_cast<void (IdentityDocument::*)() const>(&Passport::PrintID)};
And a short demo :
int main() {
array<IdentityDocument*, 1> docs = { (IdentityDocument*)(new Passport()) };
for (const auto* doc : docs) {
doc->PrintID();
}
}
Unfortunately, I see that the 'derived' method was not called. Am I using a wrong approach to implement a vtable concept?
Am I using a wrong approach to implement a vtable concept?
Yes. You have not written any code that reads your vtable, and the C++ compiler will not generate any code to read your vtable either.
When you declare a member function virtual, your compiler needs to call that function in a special way. Any call to that function should be looked up in a vtable.
When a member function is not virtual, your compiler knows that it doesn't need to look up the location of the function. It knows which function to call. No lookup needed.
In your code, you have created a vtable, but this line, calling a non-virtual function:
doc->PrintID();
Does not need a vtable, and does not check for one.
doc is an IdentityDocument*, so doc->PrintID() calls IdentityDocument::PrintID(). No lookup required, no lookup happens.
Finally I simplified my solution and got what I wanted :
#include <iostream>
class A;
struct VTable
{
void (*say_hello)(A*);
};
class A
{
public:
A()
{
vtable.say_hello = A::sayHello;
}
void sayHello()
{
vtable.say_hello(this);
}
static void sayHello(A* a)
{
std::cout << "A::sayHello" << std::endl;
}
VTable vtable;
};
class B
{
public:
B()
{
a.vtable.say_hello = B::sayHello;
}
void sayHello()
{
a.vtable.say_hello((A*)this);
}
static void sayHello(A* a)
{
std::cout << "B::sayHello\n" << std::endl;
}
private:
A a;
};
int main()
{
A* a = (A*)(new B);
a->sayHello();
delete a;
}
Related
I am sure this question has been answered before, but I am unable to find a satisfactory answer. Take the following example:
class A {
public:
A(int a, int b, int c);
//...
};
class B {
public:
B(...);
private:
A _a0;
A _a1;
A _a2;
A _a3;
};
Class B contains multiple instances of class A. I want to represent that B "owns" all of these instances. From what I know, there are a couple ways to represent this
The instances of A are declare as direct members of B (as I have shown), and thus the memory of the A instances is directly inside the B class.
B contains a bunch of unique_ptr objects to the A classes
Use the Builder design pattern to do the creation on step at a time
The reason I don't want to use (2) and (3) is that I want NO heap allocation of these objects (I am writing for an embedded system).
The problem with (1) is, since each A requires 3 constructor parameters and these parameters are not provided by B but rather by the application writer (i.e., B merely owns and uses these instances of A but does not need to know how to create them), I have the bad option of passing 12 arguments to the constructor of B in order to create all 4 As.
I am wondering if another option would be to write the constructor of B such that it takes r-values to As and then move these As into B?
For example:
class B {
public:
B(A&& a0, A&& a1, A&& a2, A&& a3) :
_a0(std::move(a0)),
_a1(std::move(a1)),
_a2(std::move(a2)),
_a3(std::move(a3))
{
}
private:
A _a0;
A _a1;
A _a2;
A _a3;
};
The one problem I can see which this solution is, what if A is a class which points/refers to some "global" resource. The constructor of A should initialize this resource and the destructor should de-initialize this resource. If A is moved, the reference/pointer to the resource also has to be moved AND the old copy of A has to be placed in some valid state which does not de-initialize the resource because ownership has been transferred. What would be the correct way to represent this?
So, your main problem is designing class A. From your description looks like it should be non-copyable, but move-constructible (and move-assignable):
The one problem I can see which this solution is, what if A is a class
which points/refers to some "global" resource. The constructor of A
should initialize this resource and the destructor should
de-initialize this resource. If A is moved, the reference/pointer to
the resource also has to be moved AND the old copy of A has to be
placed in some valid state which does not de-initialize the resource
because ownership has been transferred.
The usual way to create such a class is by using unique_ptr with a custom deleter. Suppose, you have class Resource and
Resource* init_resource(int a);
void deinit_resource(Resource*);
Then, your class A may look like:
class A {
public:
A(int a, int b, int c)
: r( init_resource(a) )
{
//...
}
private:
std::unique_ptr<Resource, deinit_resource> r;
//...
};
With this class A, your constructor design of class B will work, but this is not the only way. If you like Builder pattern but cannot use dynamic memory, then std::optional is your friend. For example:
class B
{
public:
B(){}
void set_A1(int a, int b, int c)
{
a1_ = A(a, b, c);
}
//...
private:
std::optional<A> a1_;
//...
};
Here is a solution I put together that seems to work correctly
#include <assert.h>
#include <utility>
#include <cstdint>
#include <iostream>
#include <atomic>
/*
* Some global resource
* On an embedded system, this would be the peripherals/special-purpose registers
*/
static unsigned int resource1 = 0;
static unsigned int resource2 = 0;
/*
* Often, an SDK for an MCU will provide #define statements which contain the
* the start address (as an integer) of the peripheral register(s)
*/
#define RESOURCE1_ADDR (std::intptr_t)(&resource1)
#define RESOURCE2_ADDR (std::intptr_t)(&resource2)
template <typename T>
class ResourceManager;
/**
* #brief A handle to a particular resource managed by a ResourceManager
* #note Similar to unique_ptr, a ResourceHandle may only be moved
*/
template <typename T>
class ResourceHandle {
public:
~ResourceHandle() {
std::cout << "ResourceHandle::~ResourceHandle()" << std::endl;
}
/**
* #brief Helper method to release the resource managed by this handle back
* to its appropriate resource manager.
*/
inline void release() {
assert(_addr != 0);
_manager.release(std::move(*this));
}
/**
* #brief Copy constructor
* #note Deleted because ResourceHandle is move-only
*/
ResourceHandle(const ResourceHandle& other) = delete;
/**
* #brief Assignment operator
* #note Deleted because ResourceHandle is move-only
*/
const ResourceHandle& operator=(const ResourceHandle&) = delete;
ResourceHandle(ResourceHandle&& other) :
_manager(other._manager),
_addr(other._addr)
{
std::cout << "ResourceHandle::ResourceHandle(ResourceHandle&&)" << std::endl;
assert(_addr != 0);
other._addr = 0;
}
ResourceHandle& operator=(ResourceHandle&& other) {
std::cout << "ResourceHandle::operator=(ResourceHandle&&)" << std::endl;
if (this != &other) {
_addr = other._addr;
other._addr = 0;
}
return *this;
}
operator T*() const {
assert(_addr != 0);
return reinterpret_cast<T*>(_addr);
}
T* operator->() const { return operator T*(); }
inline bool isValid() const { return _addr != 0; }
protected:
ResourceHandle(ResourceManager<T>& manager, std::intptr_t addr) :
_manager(manager),
_addr(addr)
{
std::cout << "ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)" << std::endl;
}
private:
ResourceManager<T>& _manager;
/**
* #brief The integer address of the resource being mamaged by this handle
* #note Set to 0 when invalid
*/
std::intptr_t _addr;
friend class ResourceManager<T>;
};
/**
* #brief Class which manages a particular resource by allowing a ResourceHandle
* to be "obtained" and "released"
*/
template <typename T>
class ResourceManager {
public:
constexpr ResourceManager(std::intptr_t addr) :
_resource(*this, addr)
{
}
constexpr ResourceHandle<T> obtain() {
std::cout << "ResourceHandle::obtain()" << std::endl;
assert(_resource.isValid());
return std::move(_resource);
}
constexpr void release(ResourceHandle<T> r) {
std::cout << "ResourceHandle::release()" << std::endl;
assert(!_resource.isValid());
_resource = std::move(r);
}
private:
ResourceHandle<T> _resource;
};
/**
* #brief Example class which "uses" (i.e., takes ownership of) a resource
* via a ResourceHandle
*/
class ResourceUser {
public:
ResourceUser(ResourceHandle<unsigned int> r) :
_r(std::move(r))
{
std::cout << "ResourceUser::ResourceUser(ResourceHandle<unsigned int>)" << std::endl;
//Init
std::cout << "ResourceUser -> Init resource" << std::endl;
*_r = 0;
}
~ResourceUser() {
std::cout << "ResourceUser::~ResourceUser()" << std::endl;
if (_r.isValid()) {
std::cout << "ResourceUser -> Cleanup resource" << std::endl;
*_r = 0;
_r.release();
}
}
ResourceUser(ResourceUser&& other) :
_r(std::move(other._r))
{
std::cout << "ResourceUser::ResourceUser(ResourceUser&&)" << std::endl;
}
void set(unsigned int x) {
std::cout << "ResourceUser::set()" << std::endl;
*_r = x;
}
private:
ResourceHandle<unsigned int> _r;
};
/**
* #brief Example class which "owns" two ResourceUser objects
*/
class ResourceUserUser {
public:
ResourceUserUser(ResourceUser&& a, ResourceUser&& b) :
_a(std::move(a)),
_b(std::move(b))
{
std::cout << "ResourceUserUser::ResourceUserUser()" << std::endl;
}
~ResourceUserUser() {
std::cout << "ResourceUserUser::~ResourceUserUser()" << std::endl;
}
void foo() {
std::cout << "ResourceUserUser::foo()" << std::endl;
_a.set(10);
_b.set(20);
}
private:
ResourceUser _a;
ResourceUser _b;
};
class Resource1 : public ResourceManager<unsigned int> {
public:
inline static ResourceManager<unsigned int>& instance() { return _instance; }
private:
static ResourceManager<unsigned int> _instance;
};
class Resource2 : public ResourceManager<unsigned int> {
public:
inline static ResourceManager<unsigned int>& instance() { return _instance; }
private:
static ResourceManager<unsigned int> _instance;
};
ResourceManager<unsigned int> Resource1::_instance(RESOURCE1_ADDR);
ResourceManager<unsigned int> Resource2::_instance(RESOURCE2_ADDR);
void test1() {
std::cout << std::endl << "BEGIN test1()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUser user(Resource1::instance().obtain());
user.set(20);
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test1()" << std::endl;
}
void test2() {
std::cout << std::endl << "BEGIN test2()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUserUser user(ResourceUser{Resource1::instance().obtain()}, ResourceUser{Resource2::instance().obtain()});
user.foo();
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test2()" << std::endl;
}
void test3() {
std::cout << std::endl << "BEGIN test3()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUser user1(Resource1::instance().obtain());
ResourceUserUser user2(ResourceUser{Resource1::instance().obtain()}, ResourceUser{Resource2::instance().obtain()});
user2.foo();
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test3()" << std::endl;
}
If you execute test2() the output is
ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)
ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)
BEGIN test2()
resource1 = 0
resource2 = 0
ResourceHandle::obtain()
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceHandle<unsigned int>)
ResourceUser -> Init resource
ResourceHandle::obtain()
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceHandle<unsigned int>)
ResourceUser -> Init resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceUser&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceUser&&)
ResourceUserUser::ResourceUserUser()
ResourceUser::~ResourceUser()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUser::~ResourceUser()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUserUser::foo()
ResourceUser::set()
ResourceUser::set()
resource1 = 10
resource2 = 20
END test2()
ResourceUserUser::~ResourceUserUser()
ResourceUser::~ResourceUser()
ResourceUser -> Cleanup resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::release()
ResourceHandle::operator=(ResourceHandle&&)
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUser::~ResourceUser()
ResourceUser -> Cleanup resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::release()
ResourceHandle::operator=(ResourceHandle&&)
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
I am curious though, is there any way I can get rid of those extra calls to the move constructor? For example, the ResourceManager calls the move constructor to move the handle out of itself, then the ResourceUser calls the move constructor again.
Is it possible to return a template member of a derived class by the base?
Please find the following classes:
Data.h:
#include <string>
class IData{
public:
virtual ~IData(){};
virtual const std::string& getName() const = 0;
};
template <typename T>
class DataImpl: public IData
{
public:
DataImpl(const std::string& name, T* ptrToData)
:_name(name)
,_ptrToData(ptrToData)
{};
~DataImpl(){};
const std::string& getName() const
{
return _name;
}
const T* getDataPtr() const
{
return _ptrToData;
}
private:
std::string _name;
T* _ptrToData; // <-- how to return this pointer ?
};
Component.h:
#include <vector>
#include <string>
#include "Data.h"
class Component
{
public:
Component(const std::string& name)
:_name(name)
{};
~Component(){};
const std::string& getName() const
{
return _name;
};
std::vector<IData*>& getDataList()
{
return _dataList;
};
void addData(IData* ptr)
{
_dataList.push_back(ptr);
};
private:
std::string _name;
std::vector<IData*> _dataList;
};
main.cpp:
#include <iostream>
#include <vector>
#include <string>
#include "Component.h"
#include "Data.h"
int main()
{
// primitive types
int x = 5;
float y = 5.7;
bool b = false;
// complex structures
struct complex{
int a;
std::string c;
};
complex cx;
cx.a = 5;
cx.c = "anything";
DataImpl<int> d1("x", &x);
DataImpl<float> d2("y", &y);
DataImpl<bool> d3("b", &b);
DataImpl<complex> d4("complex", &cx);
Component cmp("cmpName");
cmp.addData(&d1);
cmp.addData(&d2);
cmp.addData(&d3);
cmp.addData(&d4);
std::vector<IData*>::iterator it = cmp.getDataList().begin();
for (;it != cmp.getDataList().end(); ++it)
{
IData* ptr = *it;
std::cout << ptr->getName() << std::endl;
}
return 0;
}
Inside the loop in the main.cpp, I was accessing every DataImpl member. But I want to return/get the member variable T* _ptrToData through the base class IData but so far I did not find any way.
I have a compiler restriction to c++98
Thanks in advance.
You can try to use dynamic_cast to perform a type-safe downcast of the IData* pointer back to the pointer of the derived class (e.g. DataImpl<int>* ) . However, this may require the Run-time type information (RTTI) of the compiler enabled.
Here's an example:
for (;it != cmp.getDataList().end(); ++it)
{
IData* ptr = *it;
std::cout << ptr->getName() << std::endl;
DataImpl<int>* pInt = dynamic_cast<DataImpl<int>*>(ptr);
if (pInt) {
std::cout << "*pInt->getDataPtr(): " << *pInt->getDataPtr() << std::endl;
std::cout << "pInt->getDataPtr(): " << pInt->getDataPtr() << std::endl;
}
DataImpl<float>* pfloat = dynamic_cast<DataImpl<float>*>(ptr);
if (pfloat) {
std::cout << "*pfloat->getDataPtr(): " << *pfloat->getDataPtr() << std::endl;
std::cout << "pfloat->getDataPtr(): " << pfloat->getDataPtr() << std::endl;
}
DataImpl<bool>* pbool = dynamic_cast<DataImpl<bool>*>(ptr);
if (pbool) {
std::cout << "*pbool->getDataPtr(): " << *pbool->getDataPtr() << std::endl;
std::cout << "pbool->getDataPtr(): " << pbool->getDataPtr() << std::endl;
}
}
Based on the comments to my last question (Getter-function for derived class in derived class, when using pointer to base class), I've been told that I have to use static_cast when recasting my pointer from the base class to the derived class, in order to access the derived class. I tested that using the following code:
#include <iostream>
class class_data{
public:
int val_a = 0;
double val_b = 0.;
};
class overridden_class_data : public class_data{
public:
int val_c = 0.;
};
class overridden_class_data_II : public class_data{
public:
int val_c = 12.;
};
class BaseClass{
public:
BaseClass(){};
virtual void print_data() = 0;
virtual class_data *get_local_data() = 0;
class_data local_class_data;
};
class DerivedClass : public BaseClass{
public:
DerivedClass(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
local_class_data.val_c = 14;
};
void print_data() override{
std::cout << "Hello World\n";
}
class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data local_class_data;
};
class DerivedClassII : public BaseClass{
public:
DerivedClassII(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
};
void print_data() override{
std::cout << "Hello World\n";
}
class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data_II local_class_data;
};
void test_func(BaseClass *class_pointer){
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->local_class_data.val_a << '\n';
class_pointer->local_class_data.val_a = 5;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
class_pointer->get_local_data()->val_a = 15;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << static_cast<overridden_class_data*>(class_pointer->get_local_data())->val_c << '\n';
}
int main(void){
std::cout << "From main\n";
DerivedClass DClass;
DerivedClassII EClass;
std::cout << "DClass: \n";
test_func(&DClass);
std::cout << "EClass: \n";
test_func(&EClass);
return 0;
}
Here I have two derived classes, which use two different derived classes as class variable. To access the data of those classes I have to use static_cast onto the returned base-class pointer to cast it back to the derived class. Still, I do not want to rewrite the function test_func() for both classes, but instead use the same function for them.
Initially, I thought that I had to write the last line of the function twice, recasting the class variable pointer once to overridden_class_data* and once to overridden_class_data_II*, depending on the input class. But after testing I noticed that I do not have to do that, I can recast it to overridden_class_data*, but it still acts as if I recasted it overridden_class_data_II*. Why? Is it because both classes contain the same elements, and therefore the pointer can point to the same spot?
As for your original question, yes this is happening just because (1) the data members of your class are identically setup and (2) static_cast is not safe for such polymorphic casts.
A simple counterexample to break test_func would be(code):
class overridden_class_data : public class_data{
public:
int val_pad = 0.;
int val_c = 23.;
};
which would incorrectly then print the value 0 instead of 12 for the EClass pointer->get_local_data()->val_c.
A few ways you could go about solving this(making test_fn single use):
Correctly detect the above issue using dynamic_casts, but then test_func would need to be called with appropriate explicit template args.
Forego the casts with compile time safety by making a simple generic test_func and using covariant return types. You mentioned that your concerned about too many templates - Is it code bloat you are worried about?
#churill suggestion of using a virtual getter like get_val_c.
Here is the snippet for the 2nd method suggested - I've marked the changes I made(code):
#include <iostream>
class class_data{
public:
int val_a = 0;
double val_b = 0.;
};
class overridden_class_data : public class_data{
public:
int val_pad = 23;
int val_c = 0.;
};
class overridden_class_data_II : public class_data{
public:
int val_c = 12.;
};
class BaseClass{
public:
BaseClass(){};
virtual void print_data() = 0;
virtual class_data *get_local_data() = 0;
class_data local_class_data;
};
class DerivedClass : public BaseClass{
public:
DerivedClass(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
local_class_data.val_c = 14;
};
void print_data() override{
std::cout << "Hello World\n";
}
// use covariant return type
overridden_class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data local_class_data;
};
class DerivedClassII : public BaseClass{
public:
DerivedClassII(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
};
void print_data() override{
std::cout << "Hello World\n";
}
// use covariant return type
overridden_class_data_II * get_local_data() override {
return &local_class_data;
}
overridden_class_data_II local_class_data;
};
template <typename T>
void test_func(T *class_pointer){ // make generic
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->local_class_data.val_a << '\n';
class_pointer->local_class_data.val_a = 5;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
class_pointer->get_local_data()->val_a = 15;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->get_local_data()->val_c << '\n';
}
int main(void){
std::cout << "From main\n";
DerivedClass DClass;
DerivedClassII EClass;
std::cout << "DClass: \n";
test_func(&DClass);
std::cout << "EClass: \n";
test_func(&EClass);
return 0;
}
I got this:
class Core
{
protected:
static unsigned int id_seed;
unsigned int id;
std::string status;
public:
friend class CPU;
Core();
~Core();
virtual void procesare(std::string aplicatie) = 0;
};
class CoreScreen: public Core
{
public:
CoreScreen();
~CoreScreen();
void procesare(std::string aplicatie);
};
and corescreen.cpp:
#include "CoreScreen.h"
CoreScreen::CoreScreen()
{
}
CoreScreen::~CoreScreen()
{
}
void CoreScreen::procesare(std::string aplicatie)
{
std::string buffer;
std::ifstream file_in(aplicatie);
if (file_in.is_open()) {
std::cout << "Aplicatia " << aplicatie << " ruleaza: " << std::endl;
while (getline(file_in, buffer)) {
std::cout << buffer;
}
file_in.close();
}
else {
throw new CExceptie(APP_FAIL, " Aplicatia nu a putut rula!");
}
}
When I use in main:
CoreScreen CS1, CS2, CS3, CS4;
I get this error: 'Core' cannot instantiate abstract class.
What's the problem? I thought I have my virtual function declared in CoreScreen correctly.
As I presume you know, "Core" is an abstract class, by virtue of the fact it has a pure virtual function: virtual void procesare(std::string aplicatie) = 0;.
I presume you also know that you can't instantiate an abstract class: hence your error.
The question is:
Why does the compiler think you're trying to instantiate an instance of "Core"?
Are you?
It looks like you're trying to instantiate four CoreScreen objects: CoreScreen CS1, CS2, CS3, CS4;. If so, that should be perfectly OK.
You're correct: procesare() is virtual ("pure virtual", as it happens). You've indeed overridden it correctly in CoreScreen.cpp: it DOESN'T look like that's the problem.
Q: Did you ever implement Core::Core() and Core::~Core() anywhere? If not, how did you even compile?
Q: Are you SURE you're not trying to create an instance of "Core" anywhere (even "accidentally")?
For whatever it's worth, the following MCVE compiles and runs fine (Ubuntu 18, GCC 7.3.0):
TestCore.h:
/*
* TestCore.h
*/
#ifndef TESTCORE_H_
#define TESTCORE_H_
#include <string>
class Core
{
protected:
static unsigned int id_seed;
unsigned int id;
std::string status;
public:
friend class CPU;
Core();
~Core();
virtual void procesare(std::string aplicatie) = 0;
};
class CoreScreen: public Core
{
public:
CoreScreen();
~CoreScreen();
void procesare(std::string aplicatie);
};
#endif /* TESTCORE_H_ */
TestCore.cpp:
/*
* TestCore.cpp
*/
#include <iostream>
#include <fstream>
#include "TestCore.h"
Core::Core()
{
std::cout << "Core::Core()..." << std::endl;
}
Core::~Core()
{
std::cout << "Core::~Core()..." << std::endl;
}
CoreScreen::CoreScreen()
{
std::cout << "CoreScreen::CoreScreen()..." << std::endl;
}
CoreScreen::~CoreScreen()
{
std::cout << "CoreScreen::~CoreScreen()..." << std::endl;
}
void CoreScreen::procesare(std::string aplicatie)
{
std::cout << "CoreScreen::procesare(" << aplicatie << ")" << std::endl;;
}
int main () {
std::cout << ">>main()..." << std::endl;
CoreScreen CS1, CS2, CS3, CS4;
CS1.procesare("Testing CS1");
std::cout << "<<main()." << std::endl;
return 0;
}
SAMPLE OUTPUT:
>>main()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
CoreScreen::procesare(Testing CS1)
<<main().
You'll note that I implemented Core::Core() and Core::~Core(). If you don't need them - then don't even put them in your .h class definition.
'Hope that helps
I stumbled across this piece of code when I researched for a good example for Observer Design pattern. In main, it gets error, taking address of temporary[-fpermissive] which I dont dont understand what it is frankly. Sending a class refference to an function? Is this real life?
#include <vector>
#include <iostream>
using namespace std;
class AlarmListener
{
public:
virtual void alarm() = 0;
};
class SensorSystem
{
vector < AlarmListener * > listeners;
public:
void attach(AlarmListener *al)
{
listeners.push_back(al);
}
void soundTheAlarm()
{
for (int i = 0; i < listeners.size(); i++)
listeners[i]->alarm();
}
};
class Lighting: public AlarmListener
{
public:
/*virtual*/void alarm()
{
cout << "lights up" << '\n';
}
};
class Gates: public AlarmListener
{
public:
/*virtual*/void alarm()
{
cout << "gates close" << '\n';
}
};
class CheckList
{
virtual void localize()
{
cout << " establish a perimeter" << '\n';
}
virtual void isolate()
{
cout << " isolate the grid" << '\n';
}
virtual void identify()
{
cout << " identify the source" << '\n';
}
public:
void byTheNumbers()
{
// Template Method design pattern
localize();
isolate();
identify();
}
};
// class inheri. // type inheritance
class Surveillance: public CheckList, public AlarmListener
{
/*virtual*/void isolate()
{
cout << " train the cameras" << '\n';
}
public:
/*virtual*/void alarm()
{
cout << "Surveillance - by the numbers:" << '\n';
byTheNumbers();
}
};
int main()
{
SensorSystem ss;
ss.attach(&Gates());
ss.attach(&Lighting());
ss.attach(&Surveillance());
ss.soundTheAlarm();
}
This is ill-formed:
ss.attach(&Gates());
^^^
Gates() is an rvalue (specifically, a prvalue). You cannot take the address of an rvalue. It's not an object that has identity, so it doesn't really have an address that you can take. The language is preventing you from doing something that doesn't make sense to do. If you did store a pointer to this temporary, you'd just end up with a dangling pointer since at the end of this line the temporary Gates would be destroyed.
Since SensorSystem doesn't own its AlarmListeners, you'll have to create them up front:
Gates gates;
Lighting lighting;
Surveillance surveillance;
SensorSystem ss;
ss.attach(&gates);
ss.attach(&lighting);
ss.attach(&surveillance);