Initialize std::variant<Pointer, Pointer>? - c++

I have a class which looks something like this:
class X
{
std::variant<CComPtr<ID2D1HwndRenderTarget>, CComPtr<ID2D1DCRenderTarget>> mpRenderTarget;
void init();
}
// To early to know which member we need, it's no value until derived class calls init() method.
X::X() : mpRenderTarget(nullptr)
void X::init()
{
// Only here it is known what exactly to initialize!
// and this is going to be in derived class, this one pure virtual.
}
Problem is that this constructor doesn't compile, because variant initialization is not valid,
however if I omit initialization of mpRenderTarget in constructor then another problem is that
the variant is "ilformed" according to standard.
I just want to initalize it to some default in constructor, but how?

Simply assign it a default value of one of the types:
X::X() : mpRenderTarget(CComPtr<ID2D1HwndRenderTarget>{}) {}
You can be explicit about the default pointer value being nullptr as well:
X::X() : mpRenderTarget(CComPtr<ID2D1HwndRenderTarget>{nullptr}) {}
The important part is that you must specify which of the variant types you want to initialize the object with.

Related

Initialize array of objects in constructor

I wrote a class that holds an array of objects, which each expect a pointer to a c-struct in their constructor:
Here's some code:
class TheOtherClass
{
private:
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass::TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx)
{}
}
class MyClass
{
private:
TheOtherClass m_objects[4];
SomeCStruct* m_pMyCStruct;
public:
MyClass::MyClass(SomeCStruct* pCStruct)
: m_pMyCStruct(pCStruct)
{
m_objects[4] = {TheOtherClass(&pCStruct, 1), TheOtherClass(&pCStruct, 2),
TheOtherClass(&pCStruct,3), TheOtherClass(&pCStruct, 4)};
}
I'd actually like to initialize the member objects of MyClass in the init list of the constructor but I was reading this isn't possible?
Hence I tried the above approach but I'm always getting the error: "TheOtherClass": no appropriate default constructor available.
Another thing to mention is that the compiler I'm running is a state of the art C++03 compiler ;-) (it's code for a DSP and TI sort of doesn't wants to update the compiler)
Any help would be highly appreciated!
Since MyClass(SomeCStruct* pCStruct) constructor doesn't (can't) initialize the TheOtherClass m_objects in the member initializer list, the m_objects will need to be default constructed at first, and then this member will be reassigned with new value in the body of the MyClass constructor.
The TheOtherClass won't have a synthesized constructor since you have defined (other, non-default) ctor that takes SomeCStruct* and int. Thus, no default constructor for it in your code.
Here, we define a default constructor:
class TheOtherClass {
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass() : m_pCStruct(nullptr), m_ObjIdx(0) {} // Default ctor
TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx) {}
};
As to the MyClass. Since you've already pass the argument as a pointer MyClass(SomeCStruct* pCStruct), you don't need to take the address of it (as in &pCStruct).
And the main issue in the MyClass is that the m_objects is of class type TheOtherClass which does not define any operator=, including the one that takes brace-enclosed initializer list. So, you won't be able to do like so:
m_objects[4] = { // The operator '=' has not been defined for the TheOtherClass, also note the subscript
TheOtherClass(pCStruct, 1),
TheOtherClass(pCStruct, 2),
TheOtherClass(pCStruct,3),
TheOtherClass(pCStruct, 4)
};
Again, when you try to list initialize it, it has already been default constructed. Thus, for this approach to work you will need to define such copy-assignment operator to do this kind of assignment to an already default constructed instance of the TheOtherClass. As to how to implement this operator, it will mostly depend on the overall design and other factors which were not mentioned in this thread.
Update
If you will have the following body of the MyClass constructor, it will work:
MyClass(SomeCStruct* pCStruct) : m_pMyCStruct(pCStruct) {
// Assign to default initialized TheOtherClass object
m_objects[0] = TheOtherClass(pCStruct, 1);
}
I would advise you to check these:
Operator overloading
Constructors and member initializer lists

Setter getter methods in C++

I'm new to c++. I created following classes Into, MyWstring as follows: I tried to create setter for an object variable as setInto method. It complains no such constructor Into(). What should I do? How to create setter for this? (Basically what is my expectation is how to achieve Java like setters in C++)
Into.h
#ifndef INTO_H_
#define INTO_H_
class Into {
public:
Into(int id1);
virtual ~Into();
int id;
};
#endif /* INTO_H_ */
Into.cpp
#include "Into.h"
Into::Into(int id1) {
// TODO Auto-generated constructor stub
id = id1;
}
Into::~Into() {
// TODO Auto-generated destructor stub
}
MyWstring.h
#ifndef MYWSTRING_H_
#define MYWSTRING_H_
#include<iostream>
#include"Into.h"
using namespace std;
class MyWstring {
public:
MyWstring(wstring test1);
virtual ~MyWstring();
void assign(MyWstring m);
void setInto(Into into1);
wstring test;
Into into;
};
#endif /* MYWSTRING_H_ */
MyWstring.cpp
#include "MyWstring.h"
MyWstring::MyWstring(wstring test1) {
test = test1;
}
MyWstring::~MyWstring() {
// TODO Auto-generated destructor stub
}
void MyWstring::assign(MyWstring m)
{
m.test = L"M";
}
void MyWstring::setInto(Into into1)
{
into = into1;
}
When you construct a MyWString, the compiler will call the constructors of all base classes (you don't have any), and sub-objects. If you don't provide an argument, it will call the constructor without arguments - and you don't have one. Your choices are:
Provide a default constructor:
....
Into(int id1);
Into();
...
Into::Into() : id(0) {} // Always prefer to initialize rather than assign later
Initialize MyWString::into:
MyWstring::MyWstring(wstring test1)
: test(test1)
, into(0)
{}
Your class has an instance variable into that has no default constructor (one without arguments).
When MyWstring is created, it needs to create an instance of Into, but cannot do so because it does not know how to.
Solution 1: Give Into a default constructor
class Into {
[...]
Into() : id(0) { }
};
Solution 2: Mention into in the initializer list for MyWstring:
MyWstring::MyWstring(wstring test1)
: test(test1), into(0)
{
}
Note the additional change of assigning test in the initializer list. Otherwise it gets default-constructed and then copy-assigned, which is probably not what you want.
If into does not have a sensible default value, you might need to re-think your logic and use a pointer to an Into object instead (but make sure to use std::unique_ptr<> or similar).
Try changing your MyWstring c'tor definition to this:
MyWstring::MyWstring(wstring test1)
:
into( 0 ),
test( test1 )
{
}
You have a variable of type Into in class MyWstring, which does not have a default c'tor and hence compiler can not instantiate it by itself.
Also it is better if your MyWString class accepts the value for the variable "into" in c'tor so that you have an actual value to set, instead of setting some default value.
The compiler is complaining that you don't have a default constructor.
The default constructor is called, When you construct an object without passing any arguments, e.g.
Into into;
The default constructor is also automatically called if your class is member of another class.
The default constructor is auto-generated if there is no user-declared constructor. In your case you have the constructor Into(int id1) which prevents the compiler from auto-generating a default constructor.
So what you need is one of the three lines below
Into():id(0){};
Into() = default; // C++11 syntax
Into():Into(0){}; // call another constructor from your constructor.
Alternatively, if you have a constructor where all its arguments have default values, the compiler will use that as the default constructor. So you can also do like this
Into(int _id = 0) : id(_id){};
If you don't want a default constructor for your class then you need to call the non-default one on the constructor of your other class.
MyWstring::MyWstring(wstring test1): test(test1), into(0)
{}
Now to the next part, you are assigning an object of type Into to another object of the same type which means that the copy assignment operator is being used here. You are in luck because in your case the compiler auto-generates the copy assignment operator.

C++ a default constructor of a class calling another default constructor of another class

I have 2 classes Class A and B. I am trying to use Class B's default constructor to call class A's default constructor to intialize the values of class A in class B.
class A
{
A();
int x;
}
A::A()
{
//initialized x
x=10;
}
class B
{
B();
A aobj;
}
B::B()
{
//Calling class A's default constructor to initialize B's aobj.
aobj();
}
I received a no match call to '(aobj)'. Please help me to resolve.
Actually, you don't need to explicitly default construct members as that happens automatically unless you explicitly construct the member otherwise. In case you want to really construct a member explicitly, whether it is default construction or something else, you'll need to put your initialization into the member initializer list:
B::B()
: aobj() {
}
The expression aobj() in the body of a function tries to use the function call operator on the member aobj. Doing so may be reasonable, e.g., when aobj is of type std::function<void()>.
In the context of a statement, aobj() does not try to construct the aobj variable, rather it attempts to call it using the operator() operator overload.
Instead, try doing the construction in B::B()'s initializer list:
B::B() : aobj()
{
}
But note that this is redundant, since the default constructor for member objects will be called implicitly if omitted from the initializer list. That is, this constructor would do the exact same thing:
B::B() { }

Can we avoid the default constructor in this case?

Observation: The constructor of ClassMain needs to call Init before it can constructor a member variable a. Since the ClassA has no default constructor, the code doesn't compile.
ClassA
{
public:
// This class has no default constructor
ClassA(...){}
};
class ClassMain
{
public:
ClassMain(...) {
Init(...);
a = ClassA(...); // error: ClassA has no default constructor
// a has to been constructed after the Init is called!
}
ClassMain(...) {
Init(...);
call other functions
a = ClassA(...);
}
private:
// initialize environment
void Init(...) {}
private:
ClassA a;
};
Question> The simple solution is to provide a default constructor for ClassA. However, I would like to know whether there is a better solution to address the issue above?
The better solution is not to require an Init function at all. You're trying to reinvent constructors, and breaking their design in the process.
If Init does too much work for a constructor, then do it outside and pass the resulting resources into ClassMain as a constructor argument; notice how you're already doing all the work in the constructor's scope anyway, thereby not gaining anything appreciable over proper initialisation.
Of course, if you must perform a ton of work before initialising a, and you cannot pass in a ClassA& from the outside and initialise from that, then you're simply going to have to have a be an indirect member.
There is one nasty workaround you could use: have Init actually be a base constructor...
The obvious solution is to call Init() from the initializer list of an early member or a base class. Once this subobject is constructed its results can be passed to the constructors of other subobjects. For example, when defining stream classes I typically privately inherit from a virtual base containing the stream buffer:
struct somebuf_base {
somebuf sbuf;
// ...
};
class somestream
: private virtual somebuf_base
, public std::ostream
{
public:
somestream(someargs)
: somebuf_base(someargs)
, std::ostream(&this->sbuf) {
}
// ...
};
Since base classes are constructed in the order they appear but virtual bases before non-virtual bases, the base class containing the sbuf member is constructed first. Its constructor replaces your Init() function.
When using C++ as of the 2011 revision, you might also use forwarding constructors to share logic between multiple constructors.
It's easier to take a pointer to ClassA; So, you can instantiate it whenever you want.(after the init())
If you used a pointer, don't forget to implement the virtual destructor and release the allocated memory for the ClassA *a
If you absolutely must call some function at the start of your constructor, and can't put that setup into some base class or early-constructed member, you could use this ugly trick:
ClassMain::ClassMain(int main_param)
: a( (Init(init_arg), class_a_arg1), class_a_arg2 )
{
}
In this case: No, we cannot avoid that.
The reason is that when calling Init or any other member function you are guaranteed by the language that the object you are in exists. As a is a member of ClassMain it must be constructed before any function in ClassMain can be called.
The only chance that you have here is to refactor the code.

Execute checks before initialization list

I have a member of class A in my own class which constructor takes multiple parameters. Im forwarding parameters of my own class to the constructor of class A. But its important that these parameters are correct, so i need to check them before consructing the member of A. And heres the problem:
I could leave out the member in the member intialization list, effectively calling the default constructor. After the checks in the constructor i could then call A`s constructor in a assigment. Although, this produces a error since the destructor of A is private.
How do i solve this?
MyClass::MyClass(int someParam) : otherMember(2){
//checks for someParam
member = A(someParam); // <- produces error
}
You're going to need an accessible destructor no matter what you do. But to address your question, one option would be to call a static function to check parameters from within the initializer:
class MyClass {
private:
static void checkParam(int);
// ...
};
MyClass::MyClass(int someParam) : otherMember( (checkParam(someParam), 2) ) {
// ...
}
static void MyClass::checkParam(int someParam) {
if (...) throw someException();
}
Note that the , used there is the comma operator, not an argument separator - it evaluates both left and right expressions, and throws away the result of the left.
I see two ways of approaching this:
Make sure class A can be used with a parameter-less constructor, and set someParam in a separate method: A.SetSomeParam(someParam)
Not inherit from A, but rather hold a member object of type A, and then you can construct it whenever you like.