Pass Interface object to constructor c++? - c++

Say i have an interace like
#include<iostream>
struct Interface
{
virtual void fun() = 0;
};
struct IType : Interface
{
void fun() override
{
std::cout<<"non const fun()";
}
};
class Type
{
private:
Interface &intr; // I can't declare intr as const i need to ascess non const fun()
public:
// I put it as a const for default value
Type(const Interface& obj = IType()) : intr{const_cast<Interface&>(obj)} // Is const_cast is safe or how to do it ?
// What is god idea to do it should i need to remove const and default value but i need a default constructor
{
intr.fun();
}
};
int main()
{
Type obj;
return 0;
}
Thanks.

Reference as class member is rarely a good idea. You need an object, passed from the outside, that will outlive your class object. You cannot use default argument and you cannot use a temporary for initialization. Typically, if you need to pass different types that inherit from an interface, this is solved with (smart) pointers.
Type(const Interface& obj = IType()) : intr{const_cast<Interface&>(obj)}
//Is const_cast is safe or how to do it ?
It depends. You can cast away constness only if the real object is not const. So this:
IType itype{};
Type {itype};
would be valid, but this:
const IType itype{};
Type {itype};
would be invalid.
Your default argument is invalid anyway, because that default is a temporary object that dies immediately once constructor finishes, which means you cannot use intr member outside of this constructor.
I'm not 100% sure if const_cast is valid on temporary or not, but that doesn't matter in this case.
The solution is to use (smart) pointers:
class Type
{
private:
std::shared_ptr<Interface> intr;
public:
Type(std::shared_ptr<Interface> obj = std::make_shared<IType>()) : intr{std::move(obj)}
{
intr.fun();
}
};
The default choice for smart pointer is std::unique_ptr, but use of reference suggests that you wanted access to object from the outside of the class as well, and std::shared_ptr will allow that.

Related

Let the user pass a user-defined type as sub-class of the parameter class to define a member

The following is some architecture I have designed.
I have a class X that has a variable member Y that is a pointer (or reference, I haven't decided yet) to class A. Class A is an abstract class. The user of X can create his own derived class from A (for example B:A) and pass it to X (probably, in the constructor) which, somehow, will store it in Y.
To make this work, the user should dynamically allocate an object of type B:A and pass it to X. However, can you think of a simpler way, for the user, of doing this without having to call new? Ideally, I would like the user to simply create an object of type B:A and pass it. Then, the constructor of X, somehow, would define Y using it (maybe creating a copy of B:A). The problem is that X doesn't know which derived type is passed and what size it is.
I want to create a single constructor to which the user could pass any type derived from A as parameter, and would be converted into a member variable. It should allow the user to create his own type for taking advantage of polymorphism.
class A {...}; // Abstract class (has pure virtual members)
class B : public A {...}; // Class defined by the user
class X
{
public:
X(A &param) { /* abc is defined */ }
A* abc;
}
Some ideas I had:
Could it work a pure virtual copy assignment operator overloading at A? And having a member at B:A that specifies the size of B:A? However I still don't know how to make it work.
How to solve it? Is there maybe a better way? Thanks in advance.
To make this work, the user should dynamically allocate an object of type B:A and pass it to X. However, can you think of a simpler way, for the user, of doing this without having to call new?
Polymorphism is not dependent on new being used. It simply requires a pointer/reference to the polymorphic object. The caller could create its derived object statically, if it wants to. Just so long as the object outlives the X object that refers to it.
Then, the constructor of X, somehow, would define Y using it
That is not possible. The Y member would have to be statically typed at compile-time, ie as an A* pointer or A& reference. Unless X is written as a template class, so that the user can then specify the actual derived type being passed in.
maybe creating a copy of B:A
That is possible, but only if X is templated, otherwise A will have to declare a virtual clone() method that all derived classes override to make copy of themselves.
The problem is that X doesn't know which derived type is passed and what size it is.
Polymorphism doesn't need to know that info.
You could simply require the class to implement the copy operation (the Clone function below):
class A
{
public:
virtual ~A() = default;
virtual std::unique_ptr<A> Clone() const = 0;
};
class B : public A
{
public:
std::unique_ptr<A> Clone() const override
{
return std::make_unique<B>(*this);
}
};
class X
{
public:
X(A const& param)
: abc(param.Clone())
{
}
// allow transferring an object stored in a unique_ptr to the object
template<class T> requires (std::is_base_of_v<A, T>)
X(std::unique_ptr<T>&& param)
: abc(std::move(param))
{}
private:
std::unique_ptr<A> abc;
};
Note that if you restrict the user to transferring the ownership to of the subclass of A to X, you don't need to Clone functionality at all. You you could remove X::X(A const&) and Clone in this case. The user would still be able to create your object like this:
X x = std::make_unique<B>();
X x(std::make_unique<B>()); // alternative syntax for the above
On the assumption that class X is going to own param after it is passed in, you can do this:
#include <iostream>
#include <memory>
class A { public: virtual ~A () {} };
class B : public A { public: ~B () { std::cout << "B destroyed"; } };
class X
{
public:
X (std::unique_ptr <A> &param) : m_param (std::move (param)) { }
private:
std::unique_ptr <A> m_param;
};
int main ()
{
std::unique_ptr <A> b = std::make_unique <B> ();
X x (b);
}
When run, this code prints B destroyed. Note that, for this to work, A must have a virtual destructor.
If ownership of param is to be shared with the caller and / or other objects, use std::shared_ptr instead (but this has more overhead). Or, as #Remy says, if you can guarantee that the lifetime of param exceeds that of x, you can store a raw pointer (or reference).
Edit: As per the comments, a better implementation of the constructor of class X would be:
X (std::unique_ptr <A> &&param) : m_param (std::move (param)) { }
And then you would call it like this:
X x { std::make_unique <B> (); }
This makes it clear that x owns the object passed in.

Passing a shared pointer by reference or by value as parameter to a class

Should a shared pointer be passed by reference or by value as a parameter to a class if it is going to be copied to a member variable?
The copying of the shared pointer will increment the refrence count and I don't want to make any unnecessary copies and thus ref count increments. Will passing the shared pointer as a refrence solve this? I assume it does but are there any other problems with this?
Passing by value:
class Boo {
public:
Boo() { }
};
class Foo {
public:
Foo(std::shared_ptr<Boo> boo)
: m_Boo(boo) {}
private:
std::shared_ptr<Boo> m_Boo;
};
int main() {
std::shared_ptr<Boo> boo = std::make_shared<Boo>();
Foo foo(boo);
}
Passing by refrence:
class Boo {
public:
Boo() { }
};
class Foo {
public:
Foo(std::shared_ptr<Boo>& boo)
: m_Boo(boo) {}
private:
std::shared_ptr<Boo> m_Boo;
};
int main() {
std::shared_ptr<Boo> boo = std::make_shared<Boo>();
Foo foo(boo);
}
Pass it by value then move it into the member:
class Foo {
public:
Foo(std::shared_ptr<Boo> boo)
: m_Boo(std::move(boo)) {}
private:
std::shared_ptr<Boo> m_Boo;
};
This will be the most efficient in all cases - if the caller has a rvalue-reference then there wont be a single add-ref, if the caller has a value there'll be a single add-ref.
If you pass by const& you force an add-ref even in cases where its unnecessary. If you pass by value and then set without a std::move you may get 2 add-refs.
Edit: This is a good pattern to use if you've got a class where a move is significantly cheaper than a copy, and you have a function call which will always copy the instance passed in - as in this case. You force the copy to happen at the function call boundary by taking it by value, and then if the caller has a rvalue reference the copy need never happen at all - it will be moved instead.
shared_ptr should be treated just like any other class when passing to functions.
in this case you should pass to const reference.
why i wrote why i wrote Herb Sutter jump to min 21:50
https://www.youtube.com/watch?v=xnqTKD8uD64

Why is using the assignment operator on a dereferenced pointer to interface not a compiler error?

Why is using the assignment operator on a dereferenced pointer to a purely abstract interface not a compiler error? When could this ever be useful? It seems like it can only lead to subtle bugs as I've outlined below.
In order to have a globally accessible object, which implements an interface, with a default value, that I can later override, do I have to use a handle (pointer to a pointer -- or -- pointer to a std::unique_ptr), or is there another approach?
#include <iostream>
class Interface {
public:
virtual int Value() = 0;
};
class Implementation : public Interface {
public:
Implementation(int value) : value(value) {}
int Value() override {
return value;
}
int value;
};
// Set default value
Interface* object = new Implementation(1);
Implementation* object2 = new Implementation(2);
int main() {
// Why is this line not a compiler error?
*object = Implementation(3); // Try to override default value
*object2 = Implementation(4); // Override default value
// This outputs "14", not "34", why?
std::cout << object->Value() << object2->Value();
return 0;
}
To get around these issues, as well as allow setting the overriding the default value in unit tests, I have gone with the following approach.
// Set default value
static std::unique_ptr<Interface> object(new Implementation(1));
void SetObject(std::unique_ptr<Interface> obj) {
object.reset(obj.release());
}
int main() {
SetObject(std::make_unique<Implementation>(2)); // Override default value
std::cout << object->Value();
return 0;
}
C++ objects by default get an operator= method generated by the compiler. This operator simply applies operator= to each of the member variables, and it is not virtual. That means it will work with the members of the static type of the declared pointer. Since Interface doesn't have any members, no members will be copied. Implementation has a member, so that member will be copied.

How to initialize a non-const attribute of a const object with a const value?

I need to instantiate a const object of my class, and initialize its members pointers from const pointers. Is that possible? How to do it?
I have something of the kind:
class A:
public Base
{
public:
A():
v(nullptr)
{}
virtual void f() override
{}
private:
my_type *v;
friend void f(const my_type& orig)
{
// How to create a "const A" with "v == &orig" ?
}
};
Whether an object itself is constant and whether any of its class members are constant, are two completely separate topics.
Whether or not a members of a class can be initialized in a particular way does not depend on whether a particular instance of the class is constant, or not.
A pointer to a constant object cannot be used to initialize a pointer to a non-constant object. Your class member:
my_type *v;
is a pointer to a non-constant object (presuming that my_type itself is not a constant type).
As such, this pointer cannot be initialized to point to a constant object.
Whether or not some instance of the class, containing this member, is constant, or not, is not a factor.

C++: References as constructor arguments, help

I have a base class(Base) whose constructor takes a reference as argument. In my derived class its constructor, I call the superclass-constructor and of course I need to pass a reference as argument. But I have to obtain that argument from a method of which the return type is by value...
I will give a short example:
class Base
{
public:
Base(MyType &obj) { /* do something with the obj */}
};
class Derived : public Base
{
public:
Derived(MyOtherType *otherType) :
Base(otherType->getMyTypeObj()) // <--- Here is the error because (see *)
{
// *
// getMyTypeObj() returns a value and
// the Base constructor wants a reference...
}
};
class MyOtherType
{
public:
MyType getMyTypeObj()
{
MyType obj;
obj.setData( /* blah, blah, blah... Some data */);
return obj; // Return by value to avoid the returned reference goes out of scope.
}
};
How can I solve this problem?
Change the Base class to:
class Base
{
public:
Base(const MyType &obj) { /* do something with the obj */}
};
Update: If you want to modify obj you cannot obviously have a const reference. In that case you can either:
1)Pass the parameter by value. That will have the overhead for the copy but avoid having to free it explicitly later.
2) Change MyOtherType::getMyTypeObj() to
MyType& MyOtherType::getMyTypeObj()
{
MyType* obj = new MyType();
obj->setData( /* blah, blah, blah... Some data */);
return *obj;
}
In this case, remember to delete the object after you are done with it.
Seriously? Your question has the answer in it. Change either the type of the parameter to the Base constructor, or the type of the return value of getMyTypeObj() so that the types are compatible.
The problem is caused by the GetMyTypeObj() returning a copy of 'obj', which is stack-based, so the compiler makes a temporary variable inside your constructor, the scope of which is just that Base() construction call.
It seems to me that there are two ways to solve this.
Change the Base constructor to accept a MyType object by value instead of by reference. This will copy the temporary object and solve scope problems.
Alternatively, you can make a copy of the MyType object in Derived and pass a reference to that.
class Derived : public Base
{
public:
Derived(MyOtherType *otherType) :
Base(m_myType) ,
m_myType(otherType->getMyTypeObj())
{
// ...
}
private:
MyType m_myType;
};
Option 1 is simpler and I would generally recommend it.
Option 2 is just in case some other constraint prevents you changing the Base constructor,