This question already has answers here:
Inheriting constructors
(8 answers)
Closed 8 years ago.
I just want to check this:
If I have a derived class that has no new members. In case that the base class has already a long constructor (many parameters), the creation of the constructor in the derived class that just throws all the parameters to the base constructor is somewhat a boring (and obviously not necessary) process. Is there a way to tell the compiler to do it automatically? I suppose not, but just needed to check. I haven't found anything on this topic but still sorry for a duplicate if this is the case...
//I'm not interested in IDE automatic generation features (although I would welcome an advice of that type either), just a compiler...
You could use constructor inheritance (available since C++11)
In the definition of the derived class write:
public:
using base_class::base_class;
where base_class is your base class.
It really depends on the version of C++ you are targetting.
The first answer is that in C++11 it is easy:
you can either use inheriting constructors
or perfect forwarding
Implementation:
// Inheriting
struct D: B { using B::B; };
// Forwarding
struct D: B {
template <typename... T>
D(int a, T&&... args): B(std::forward<T>(args)...), _a(a) {}
int _a;
};
As demonstrated, while more verbose perfect forward is also more versatile.
If you are stuck in C++03, though, all is not lost: just refactor the base constructor so it takes less parameters (ideally one):
// Before
struct B { B(int a, int b, int c, ...); };
// After
struct Pack { Pack(int a, int b, int c, ...); };
struct B { explicit B(Pack p); };
Easy Peasy.
If you are initializing several parameters in the base constructor and their values are being passed to the constructor, you can overcome this problem without C++11 by implementing setX() functions instead of initializing the values in the constructor.
BaseClass::BaseClass(int arg1, int arg2, int arg3, ...) :
_member1(arg1),
_member2(arg2),
_member3(arg3),
...
{}
Change it to:
BaseClass::BaseClass() :
_member1(0),
_member2(0),
_member3(0),
...
{}
void BaseClass::setMember1(int value) { _member1 = value; }
Related
I have some classes that look like this:
struct foo
{
foo() = delete;
explicit foo(int id) :
id(id)
{}
virtual ~foo() = default;
int id;
};
template<typename T>
struct MyClass : foo
{
MyClass() = delete;
MyClass(int id, T value) :
foo(id),
value(value)
{}
T value;
}
And it has worked pretty well up until now where T is a double, a bool, etc.
Unfortunately, CPU manufacturers decided to start putting more logical cores in their products, and now I have to write a bunch of multithreaded code (thanks guys).
The problem arises when trying to do something like
MyClass<std::atomic_flag> bar{0, ?????????????} //ATOMIC_FLAG_INIT doesnt fix it
As it attempts to use the deleted copy constructor std::atomic_flag(const std::atomic_flag&). I can see where its trying to do the copy, and the only possible solution I've come up with would involve manual allocation of memory and almost by-hand construction of members using placement-new.
Is there an easier way of doing this? How might the constructor of MyClass<T> be structured to allow generic types as well as special things that don't want to be moved/copied?
I'm using MSVC v140, so no C++17 or later features :(
Rather than taking an instance of the object to create, you can construct it inside your object by instead taking parameters of the type you wish to construct your class with. This will not work directly with std::atomic_flag due to the limitations of initializing with ATOMIC_FLAG_INIT (until C++20, that is), but would be fine with something like std::atomic<bool>.
For example:
template <typename T>
struct MyClass : foo {
MyClass() = delete;
// list of parameters to pass to value's constructor
// if this is only going to be with primitive-like types,
// you could take Args by value instead of forwarding reference
template <typename... Args>
explicit MyClass(int id, Args&&... args)
: foo(id), value(std::forward<Args>(args)...)
{}
T value;
};
Then you should be able to do
MyClass<std::atomic<bool>> bar{0, false};
I was happy to find out that in C++11 we can inherit constructors like:
class Foo
{public:
Foo(int a, double b, std::string name, char somethingElse);
};
class Derived : public Foo
{public:
using Foo::Foo;
};
But I'm finding that I'm often extending the base class where there might be maybe one or two extra features, and I need to initialise a couple extra members by maybe passing as extra argument or something. In this case is seems I have to rewrite the constructor and pass all the arguments to the base one. I'm wondering if there is a better solution. I thought maybe just using the inherited constructor and then initialising the extra member on the next line after construction, but it doesn't seem right:
Derived d = Derived(6, 6.0, "name", 'a');
d.extraMember = 4;
d.funcptr = &somefunction;
I figured it was an excellent feature but then I realised more and more that my extended classes needed extra initialisation info.
Here's my example from my code:
struct Window
{
Window(Window* parent, vec2 position, vec2 size, const String& name);
};
struct ConsoleWindow : Window
{
using Window::Window;
// But I've had to rewrite the constructor again because in this constructor I do stuff like
//GUI::bIsConsoleWindowActive = true;
//GUI::unselectWindow();
//GUI::selectedWindow = this;
}
It seems to me you can't add extra things to the construction process without rewriting the constructor and calling the base and passing all the values. This is common throughout my classes.
If your base classes are copyable/moveable and not abstract, you can push the burden of constructing the base class onto the declaration of the derived object. Just accept a base object:
Derived(Base b, int extraMember) :
Base(std::move(b)), extraMember(extraMember)
{
}
Where the declaration becomes this
Derived d{Base{6, 6.0, "name", 'a'}, 4};
That isn't perfect either, since it places certain requirements on your base classes that may not hold. And if it looks like aggregate initialization to you, then that's because this sets out to mimic it.
I'm afraid the only way that can definitely be adapted to any situation, is to spell out a new c'tor like you do now.
It wasn't clear from your question if you are able to change the base class. Assuming you are, you might consider packaging up your base constructor arguments into a struct, which could be forwarded up from the derived constructor.
This is often seen when implementing the builder design pattern, which is one way to solve the telescoping constructor anti-pattern you're describing.
struct FooParts {
int i;
double d;
string s;
char c;
};
class Foo {
public:
Foo(FooParts const & parts) : parts(parts) {}
private:
FooParts parts;
};
class Derived : public Foo {
public:
Derived(FooParts const & parts, bool extra) : Base(parts), member(extra) {}
private:
bool member;
};
I'm not sure, from your question, if you realize that you can call the base constructor from your derived constructor. Using your example:
struct Window
{
Window(Window* parent, vec2 position, vec2 size, const String& name);
};
struct ConsoleWindow : Window
{
ConsoleWindow(Window* parent, vec2 position, vec2 size, const String& name, int otherValue)
: Window(parent, position, size, name)
{
// do something with `otherValue` here.
}
};
See for example here: calling the base class constructor in the derived class constructor
The most straightforward way to do what you described is to use the base class constructor in the initialization list of the derived class:
class Foo
{public:
Foo(int a, double b, std::string name, char somethingElse);
};
class Derived : public Foo
{
public:
Derived::Derived(int a, double b, std::string name, char somethingElse,
int _extraMember, char derivedSpecificThing) :
// Initialization list starts here
Foo(a, b, name, somethingElse),
extraMember(_extraMember)
{
// Do something with derivedSpecificThing etc.
}
private:
const int extraMember;
};
using Foo::Foo only exposes the constructor of the base class as an additional constructor for your derived class. Of course, the constructor of the base class cannot initialize the additional members of the derived class that it knows nothing about.
I've ve something like this:
class A {
public:
A(int a1,int a2,int a3) {
}
}
class B: public A {
public:
B(int a1,int a2,int a3) : A(a1,a2,a3) {
.. Do Some More Init for B ...
}
}
Is it possible to write the constructor in a a shorter form?
The Constructor of the base class should be called with the same arguments. But I don't want to list all of the arguments explicit. And I need to do some special initialization stuff for class B.
I think something like this:
class B: public A {
public:
B(int a1,int a2,int a3) : A(...AUTOARG...) {
.. Do Some More Init for B ...
}
}
Is this possible in C++/11?
If there is no code happening inside B's constructor and you simply want to allow its construction in the same ways A is constructible, you can inherit A's constructors:
class B: public A {
public:
using A::A;
};
This will give B all the same constructors as A has.
If, as the edited question says, B's constructor is not empty, you can still get "do all A does plus some more" in a generic (but not as nice) way using a "catch-all" constructor with perfect forwarding:
class B: public A {
public:
template <class... Arg>
B(Arg&&... arg) : A(std::forward<Arg>(arg)...) {
//.. Do Some More Init for B ...
}
}
Note that this changes B's behaviour slightly with respect to type traits. It now seems constructible from anything, but using incorrect arguments will fail to compile. If you also need the class to play nice with constructibility detection traits etc., you can conditionally disable the incorrect instantiations using SFINAE.
Better still, inherit the constructor. This is a new feature from C++11:
class B: public A {
public:
using A::A;
};
Unfortunately though, if you want the B constructor to do additional things, then you'll need to write it out longhand as you currently do.
This question already has answers here:
Is Template of derived object a subclass of template of base type
(5 answers)
Closed 8 years ago.
I have a template class that replaces direct construction of objects with just storing them for future purpose.
template<typename T>
typedef struct Construction{
int arg;
} Construction;
Now I want to pass a std::vector< Construction< Base > > to a function that should then call the constructors of every Element with the given argument.
This works when I only use the base type, but as soon as I try to mix base and derived types, problems emerge:
Construction<Base> construct = Construction<Derived>(5);
This won't work, while a regular assignment like Base& b = Derived(5); does.
Why does this not work?
This sounds like a lazy factory pattern. As you say in a comment, Constr<Base> does not hold enough information to construct a Derived. So when storing in a vector, you should use pointers rather than values. If you are willing to use the free store for the final objects, one solution is the following:
struct Base { int x; };
struct Derived : public Base { Derived(int x) : Base{x} { } };
template<typename T>
struct Constr;
template<>
struct Constr<Base> {
virtual std::unique_ptr<Base> make() const = 0;
};
template<typename T>
struct Constr : Constr<Base> {
int arg;
Constr(int arg) : arg{arg} { }
std::unique_ptr<Base> make() const override
{
return std::make_unique<T>(arg);
}
};
int main() {
Constr<Derived> a{5}, b{2}, c{8};
std::vector<Constr<Base>*> v{&a, &b, &c};
// later...
std::vector<std::unique_ptr<Base>> u;
for (auto& i : v)
u.push_back(i->make());
for (auto& i : u)
std::cout << i->x << " "; // 5 2 8
}
For this to work, we now make Constr<Derived> derive Constr<Base>. So we can use pointers/references to such objects following the same rules as pointers/references to Base/Derived, without defining any special constructors.
Note the forward declaration of Constr: this is needed because specialization Const<Base> needs to be defined before the general template; in turn, this is needed because the latter implicitly instantiates the former (by deriving it).
I cannot think of a simple solution without the free store, though. The only possibility is to use a raw memory buffer, either as a data member of Constr<Base>, or passed as an argument to make(). But this needs some work and will always have an upper bound on the size of Derived. Or, we could automatically choose between stack/free store depending on object size; this is generic but needs even more work.
It does not work, because instantiations of class templates are not related via a subclass-superclass relationship, even if the types, used in the instantiation are.
In many cases you can solve the problem, by providing a constructor template and/or assignment operator template to your original template, like:
struct Base {
int x;
};
struct Derived : public Base {
int y;
};
template<typename T>
struct Constr {
T t;
Constr() = default;
template<typename U> Constr(const Constr<U> &a) : t(a.t) {}
};
int main() {
Constr<Derived> a;
Constr<Base> b = a;
// Constr<Derived> c = b; // error, as it should
}
This question already has answers here:
Declaring a variable with "class " keyword vs Declaring one without "class" keyword in function signatures
(4 answers)
Closed 8 years ago.
I'm studying code given to me and I see:
AFPSGameMode::AFPSGameMode(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP) { }
I'm specially curious about the use of the class keyword. Is this standard C++ and if so what does it mean?
Thank you.
The class keyword is allowed here, it's just rare to see it placed here since it can either be completely omitted (if this class has been previously declared) or replaced with the forward declaration:
void foo(const class FPostConstructInitializeProperties& p){ ... }
which is equivalent to:
class FPostConstructInitializeProperties; // <-- forward declaration
void foo(const FPostConstructInitializeProperties& p){ ... }
Don't get confused with the weird naming conventions. The snippet you have provided expresses something like this:
class B{
public:
B(){ }
B(const B& b){ };
};
class A{
public:
B my_b;
A(const class B& b) : my_b(b) { } // <-- class keyword in ctor's param decl.
};
that could be used for example like this (but I guess it's clear enough already):
int main() {
B b;
A a(b);
}
As it was old C, if you have struct say,
struct account
{
int field;
..
};
You can use it for creating its variables (objects) like,
account obj;
or,
struct account obj;.
Same is for class, you may use it, or avoid it. But it is usually not used, but permitted.