Is it possible to initialize abstract base class' protected member for all derived objects without writing the same initializer list in all derived class constructors? So that it acts like a static member for all derived objects. What I want is something like this (except it doesn't work) Read it like a pseudo code:
A.h
class A {
public:
A(string fn);
virtual ~A();
virtual void open_file() = 0;
protected:
string fileName;
};
A.cpp
A::A(string fn) : fileName {fn} {} //Initializer list is written only once here
A::~A() {}
B.h
class B : public A {
public:
B();
~B();
void open_file() const override;
};
B.cpp
B::B() {} //No initializer list for A::fileName here
void B::open_file() const {
ifstream SomeFile(fileName); //Use base class' protected member
..... //Do some stuff with open file
}
And imagine there's also a C derived class without an initializer list for A here that has a different overriden open_file function..
main.cpp
string fname = {"foo.txt"};
A* APtr = new B(fname); //This initializes A's fileName for all derived objects as "foo.txt"
Aptr->open_file(); //B opens foo.txt
fname = "bar.txt";
A* A2Ptr = new C(fname); //Now fileName that both B and C consume is changed to "bar.txt"
A2Ptr->open_file(); //C opens bar.txt
APtr->open_file(); //B now opens bar.txt
You deklared the constructor from B: B(); but you try to use it A* APtr = new B(fname); So the compiler can't find any matching constructor.
initialize abstract base class' protected member for all derived objects without writing the same initializer list in all derived class
Why not?
A.hpp
class A
{
public:
A( string fn = "") : fileName(fn){} // you can give an default path if prefered.
};
B.hpp
class B : public A
{
public:
B( string fn = "") : A( fn ) {} //c++11 feature: call base constructor.
}
Other possible solutions were:
global variable (dirty and unsafe! - Please don't do it.)
static variable in A. But you can only open one file the same time.
give A setter and getter for fileName. And use it that way:
main.cpp
B* b = new B();
b->setFileName("foo.txt");
b->openFile();
Related
The crux of the issue is I want to create a vector of base pointers to reference children objects. However I'm having issues accessing the methods of the children. I've seen examples of downcasting online but I don't feel it's the best thing for me since I want to keep my code generic. Please look below for a sample of what I'm trying to accomplish.
class Base
{
public:
stuffx;
private:
stuffy;
}
template<typename U>
class Child : public Base
{
public:
Child(
std::function<U()> getterFunc,
std::function<void(U)> setterFunc
):
mgetter(getterFunc),
msetter(setterFunc)
{
}
U getFunction() const {return m_getter();}
void setFunction(U input) const {return m_setter(input);}
private:
observableValues() {}
std::function<U()> m_getter;
std::function<void(U)> m_setter;
}
int main()
{
std::vector<std::shared_ptr<Base>> Dummy = {std::make_shared<Child<int>> (std::bind(..), std::bind(...)),
std::make_shared<Child<string>> (std::bind(..), std::bind(...)) };
Dummy.at(0)->getGFunction(); // this throws an error as out of scope.
(dynamic_cast<Child<int>>(Dummy.at(0))->getGFunction(); // this is ok
}
In this example above my vector is of size 2 which is manageable but my goal is to serialize c++ classes to a psql server and may have to handle vectors of size 30+. My next question is is there a way to automate this in a for loop taking into the account the type deduction that may need to be performed for typename U.
int main()
{
std::vector<std::shared_ptr<Base>> Dummy = {std::make_shared<Child<int>> (std::bind(..), std::bind(...)),
std::make_shared<Child<string>> (std::bind(..), std::bind(...)) };
std::vector<std::shared_ptr<Base>>::const_iterator it_base = Dummy.begin();
for (; it_base != Dummy.end(); ++it_base)
{
//insert method here for downcasting
}
}
I pass a function pointer to a function using functional, and use a constructor initialization to save it in a local variable for later use. How do I assign a default value to the parameter.
Example:
function<void()> BEGINFILE;
somefunct(function<void()> BEGINFILE): BEGINFILE(BEGINFILE) {}
But I can't seem to do:
void nullfunct() {}
function<void()> BEGINFILE;
void somefunct(function<void()> BEGINFILE = nullfunct): BEGINFILE(BEGINFILE) {}
or:
void nullfunct() {}
function<void()> BEGINFILE;
somefunct(function<void()> BEGINFILE) {
BEGINFILE = BEGINFILE;
}
I've also read that functional is deprecated/removed in C++17. I've tried to find what C++17 does without success.
I suppose that somefunct is a class (or a struct) and that with
void somefunct(function<void()> BEGINFILE): BEGINfILE(BEGINFILE) {}
do you mean a constructor of somefunct.
First (secondary) problem: constructors doesn't return values, so remove the initial void.
For the main problem I suppose that you have the problem when the default function (nullfunct()) is a non static member function.
I mean, in this case
struct somefunct
{
void nullfunct() {}
std::function<void()> bf;
somefunct (std::function<void()> bf0 = nullfunct) : bf{bf0}
{ }
};
Unfortunately, a non-static member function is something strange, very different from a regular function, and you can't assign it to a std::function.
I see three ways to solve this problem.
transform it in a static one
A static member function doesn't depend from an instance of the class so is the same type of object of a regular function and can be assigned to a std::function, so if you can transform nullfunct() in a static member, you can write
struct somefunct
{
static void nullfunct() {}
std::function<void()> bf;
somefunct (std::function<void()> bf0 = nullfunct) : bf{bf0}
{ }
};
make nullfunct() an regular function.
If you can make nullfunct() a regular (not member of a class or struct) function, it becomes compatible with std::function, so
void nullfunct() {}
struct somefunct
{
std::function<void()> bf;
somefunct (std::function<void()> bf0 = nullfunct) : bf{bf0}
{ }
};
initialize with an empty function and set with a wrapping lambda
If you can't transform somefunct() in a static member function (way 1) or in regular function (way 2), you can wrap the call of somefunct() in a lambda function that you can assign to your std::function.
Unfortunately, this lambda function has to capture the this pointer and can't do it if is defined as a default value for the argument of the constructor so the way I see is initialize the std::function with an empty std::function and, in the body of the constructor, if the member contains an empty function, assign the lambda.
I mean
struct somefunct
{
void nullfunct() {}
std::function<void()> bf;
somefunct (std::function<void()> bf0 = {}) : bf{bf0}
{ if ( not bf ) bf = [this]{ this->nullfunct(); }; }
};
There is a custom defined map, with an element std::function()>.
The lambda code is working, but I don't know how to expand it to a normal formation. The code is following.
class TestA{
public:
TestA() {}
~TestA() {}
TestA(const TestA &) {}
static void print()
{
cout << __FUNCTION__ << endl;
return;
}
};
void testComplexMap1()
{
typedef map<string, std::function<std::unique_ptr<TestA>()>> TempMap;
TempMap m;
// the lambda format code, it works
//m.insert({ "TestA", []() {return std::unique_ptr<TestA>(new TestA());}});
// I want to expand it, but failed.
TestA *t = new TestA();
//function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t));
function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t)()); //warning here
//m.emplace("TestA", fp); // compile error here
}
Any help will be greatly appreciated.
fp is not initialized with a function so compilation fails.
You can expand it like this:
TestA *t = new TestA();
std::unique_ptr<TestA> UT(t);
auto func = [&]() { return move(UT);};
std::function<std::unique_ptr<TestA>()> fp(func);
m.emplace("TestA", fp);
See DEMO.
In C++ everything that looks like it could be a declaration is treated as such.
This means the line
function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t)());
is interpreted as:
fp is the declaration of a function returning an std::function<unique_ptr<TestA>()> and expecting a parameter called t which is a function pointer to a function returning a std::unique_ptr<TestA> and getting no parameter. (Which is not what you intended.)
This also means that the t in this line is not the same t as in the previous line.
You have to pass fp something that is actually callable like this:
std::unique_ptr<TestA> f() {
return std::make_unique<TestA>();
}
void testComplexMap1() {
// ...
function<unique_ptr<TestA>()> fp(f);
m.emplace("TestA1", fp);
}
If you want to add a function to the map that wraps an existing pointer into a unique_ptr you would need either a functor:
class Functor {
public:
Functor(TestA * a) : m_a(a) {}
~Functor() { delete m_a; }
std::unique_ptr<TestA> operator()(){
auto x = std::unique_ptr<TestA>(m_a);
m_a = nullptr;
return std::move(x);
}
private:
TestA * m_a;
};
void testComplexMap1() {
//...
TestA * t = new TestA();
m.emplace("TestA", Functor(t));
}
Or a lambda with capture:
void testComplexMap1() {
//...
TestA * t = new TestA();
m.emplace("TestA", [t](){ return std::unique_ptr<TestA>(t); });
}
The lamda is translated more or less to something like the Functor class. However in each case you have to be really careful: The functions in the map that encapsulate an existing pointer into a std::unique_ptr can and should only be called once.
If you don't call them, memory allocated for t won't be freed. If you call them more than once you get either a std::unique_ptr to nullptr (in my Functor class variant) or a more than one std::unique_ptr tries to manage the same memory region (in the lambda with capture variant), which will crash as soon as the second std::unique_ptr is deleted.
In short: I would advice against writing code like this and only put functions in the map that are callable multiple times.
I'm trying to get a variable declared in the main into the private variables of my class without passing it as an argument for the constructor. I need to link the interrupt controller to multiple hardware interrupts without re initializing the interrupt instance and thus overwriting it.
XScuGic InterruptInstance;
int main()
{
// Initialize interrupt by looking up config and initializing with that config
ConfigPtr = XScuGic_LookupConfig(INTERRUPT_DEVICE_ID);
XScuGic_CfgInitialize(&InterruptInstance, ConfigPtr, ConfigPtr->BaseAddr);
Foo foo;
foo.initializeSpi(deviceID,slaveMask);
return 0;
}
And the implementation of the class Foo:
class Foo
{
// This should be linked to the one in the main
XScuGic InterruptInstance;
public:
// In here, the interrupt is linked to the SPI device
void initializeSpi(uint16_t deviceID, uint32_t slaveMask);
};
The deviceID and slaveMask are defined in a header which is included.
Is there some way to achieve this?
You can initialize a private class reference member with a constructor that uses the global variable, so then there is no need to pass it in the constructor:
XScuGic InterruptInstance_g; // global variable
class Foo {
private:
const XScuGic& InterruptInstance; // This should be linked to the one in the main
public:
Foo() : InterruptInstance{InterruptInstance_g} {}; // private variable is initialized from global variable
void initializeSpi(uint16_t deviceID,uint32_t slaveMask); // In here, the interrupt is linked to the SPI device
};
int main()
{
// Initialize interrupt by looking up config and initializing with that config
ConfigPtr = XScuGic_LookupConfig(INTERRUPT_DEVICE_ID);
XScuGic_CfgInitialize(&InterruptInstance,ConfigPtr,ConfigPtr->BaseAddr);
Foo foo{}; // reference is not required as it will come from the global variable to initialize the private reference member
foo.initializeSpi(deviceID,slaveMask);
return 0;
}
I am new to c++ and am trying a basic factory pattern in C++11 but is failing with error: 'X' does not refer to a value.
Any suggestions?
Test Code:
X instance = X.createNewInstance();
Original Class
class X
{
public:
static X createNewInstance() {
return X();
};
void foo() ;
private:
X(){};
};
You have to call static member functions with ::
X instance = X::createNewInstance();