RVO when converting return value - c++

I struggle with the complexity of conversions and casting, and I can't find advice online that clearly guarantees efficient conversion on function return. I have two classes, Base and Derived, where Derived has no extra data members over Base. I have a named constructor for the base class that I want to return using RVO and cast to an object of the derived type with as little overhead as possible.
class Base {
public:
static Base namedConstructor(int n){
return Base(n);
}
protected:
Base(int n) : member(n){
}
int member;
};
class Derived : public Base {
static Derived nC2(int n) {
Derived derived = namedConstructor(n);
// Error: no suitable user-defined conversion from "Base" to "Derived"...
// modify derived
return derived;
}
};
Is there a way to fix the error that satisfies all the following requirements?
No use of RTTI. Dynamic casting seems unnecessary.
Only one definition of namedConstructor in case I need to modify it. If necessary, I can make it a template, but I am interested in the alternatives.
namedConstructor should take advantage of RVO in nC2.
The conversion should not silently fail if I add or remove data members from either the base or the derived class (something similar to reinterpret_cast may do this).

Add a private ctor. to Derived, which constructs it from a Base:
Derived(const Base& base) : Base(base) {
}
If later you add extra member variables to Derived, initialize them also.
This is standard-compliant (although a little bit weird), and will be optimized away in release builds.

I've added constructors and with g++ 3.0 there is copy elision:
class Base {
public:
static Base namedConstructor(int n){
return Base(n);
}
protected:
Base(int n) : member(n){
std::cout << "Create Base" << std::endl;
}
Base (const Base & b) : member (b.member) {
std::cout << "Copy Base" << std::endl;
}
int member;
};
class Derived : public Base {
public:
Derived () : Base (0) {
std::cout << "Create Derived" << std::endl;
}
Derived (const Base & b) : Base(b) {
std::cout << "Create Derived from base" << std::endl;
}
int val () { return member; }
static Derived nC2(int n) {
return namedConstructor(n); //derived;
}
};
int main ()
{
Derived d = Derived::nC2(1);
std::cout << "Value: " << d.val() << std::endl;
return 0;
}
The output from this is:
Create Base
Copy Base
Create Derived from base
Value: 1
so one Base creation, one copy of Base when creating Derived and the Derived itself.
There are no copies from namedConstructor exit or nC2, nor for the assignment in main.
I've compiled this with -O0 but with those so small functions may be there is optimization here and those are removed.

Related

Calling a class with an abstract base class from a derived class --safely

I'd like to call the class Foo which has the abstract class Base in its ctor. I'd like to be able to call Foo from Derived which is derived from Base and use Derived's overriding methods rather than Base's.
I'm only able to do this by using a raw pointer as indicated. Is there any way to do this without raw pointers? I tried std::shared_ptr but the compiler complains about abstract classes. Or perhaps is there a better way?
#include <iostream>
class Base {
public:
Base() {
std::cout << "Hello from Base." << std::endl;
}
virtual void show() const = 0;
};
class Foo {
public:
explicit Foo(const Base *s) { // can I avoid this raw pointer?
std::cout << "Hello from Foo." << std::endl;
s->show();
}
Base *s;
};
class Derived : public Base {
public:
Derived() : Base() {
std::cout << "Hello from Derived." << std::endl;
Foo(this);
}
void show() const override {
std::cout << "Hi, I'm Derived::show()." << std::endl;
}
};
int main() {
Derived();
return EXIT_SUCCESS;
}
which produces the following output:
Hello from Base.
Hello from Derived.
Hello from Foo.
Hi, I'm Derived::show().
The code can be rewritten with const reference to Base as
#include <iostream>
class Base {
public:
Base() {
std::cout << "Hello from Base." << std::endl;
}
virtual void show() const = 0;
};
class Foo {
public:
explicit Foo(const Base& b) : s(b) { // member initialization list to set s
std::cout << "Hello from Foo." << std::endl;
s.show();
}
const Base& s;
};
class Derived : public Base {
public:
Derived() : Base() {
std::cout << "Hello from Derived." << std::endl;
Foo(*this); // the parameter would be the object itself *this, instead of a pointer this
}
void show() const override {
std::cout << "Hi, I'm Derived::show()." << std::endl;
}
};
int main() {
Derived();
return EXIT_SUCCESS;
}
A reference should be initialized in a member initializer list of the constructor.
When using a raw pointer or a reference 'Foo' should not own 'Base', i.e. Foo is not responsible for destroying Base and the lifetime of Base should be guaranteed by the owner of Foo.
You have to make sure that Base (=Derived in this case) outlives Foo. That is guaranteed, if the Foo object is owned by Derived, e.g. as member or local variable. Then before Base=Derived is destroyed, Foo is destroyed.
You can use normal references instead of const references, but then the same for the constructor parameter as well as the member variable.
A raw pointer (in comparison to a reference) is idiomatic in cases,
where the parameter can also be the nullptr instead of a valid object or
where the pointer is exchanged with another one during the lifetime of the object.
The first case could be handled by std::optional instead, the second one with assignment of a lightweight object ('view'), which basically encapsulates a pointer or a reference.
So very few cases (e.g. low-level code, data-structures or for compatibility with C) are left, where raw pointers would still be used in modern C++. And even in those cases, having a wrapper object, which just stores a reference as member variable, would have the same performance (and in practice also the same memory layout) as raw pointers, but are much more clean and safe to use.
In some cases, you would prefer a raw pointer to std::optional for performance reasons, when execution speed or memory size really matters. As alternative, a reference to nullptr is not allowed in C++.

How to return referece to base class in C++

I have a base struct which include 2 members of1 and of2.
The Derived class derived inherent it,
which has a function to return a reference to member of Base class.
I hope Derived can be used in the main as following:
struct Base {
public:
std::ofstream of1;
std::ofstream of2;
};
class Derived : public Base {
public:
Base& write_file() {
return Base;
}
};
int main (){
Derived d;
d.write_file().of1 << "I'm of1" << std::endl;
d.write_file().of2 << "I'm of2" << std::endl;
}
Compiler throws error about return Base :
type name is not allowed
How do I fix it?
Base is a class and it is not an expression that can be returned.
You can get pointer to the current object with the keyword this. You can indirect through that pointer to get a reference to the current object. That reference implicitly converts to reference to base. So, correct solution is:
Base& write_file() {
return *this;
}

How to avoid Copy in Derived class operation?

I have the following class structure:
class Base{
public:
Base() {}
Base(const Base& b){
cout << "Base Copy" << endl;
*this = b;
}
Base baseOperation(Base& base){
return Base();
}
};
class Derived : public Base{
public:
Derived(){}
Derived( const Base &d ) : Base(d)
{
cout << "Derived Copy: " << endl;
}
Derived operation(Derived& input){
return baseOperation(input);
}
};
Base is basically a library I am using. It has an operator called baseOperation, that takes in itself and returns an output; I want to wrap around that output but without making both a copy of base and of derived. It is making double copies now which slows my program down. Is there a way to avoid this
The only copy here could be while constructing Derived object in the return statement of
Derived operation(Derived& input){
return baseOperation(input);
}
All other copy operations are eliminated by RVO. Of course you can change copying to moving if you have access to sources of Base. But maybe it is worth to consider aggregation instead of inheritance.

"instantiating a derived class object" - C++

I am new to C++ and learning the basics of this language. I read this line in a book "Instantiating a derived-class object begins a chain of constructor calls". Can someone please explain what does this statement means? There was no explaination given in the book. Please help.
It means that if you have a base class and a derived class:
struct A
{
A() { std::cout << "constructing A\n"; }
};
struct B : A
{
B() { std::cout << "constructing B\n"; }
};
then instantiating the derived class:
int main()
{
B b;
}
invokes the constructor not only for the derived class, but also for the base class:
constructing A
constructing B
and this "chain" of automatically-invoked constructors gets longer the more bases you have (i.e. the deeper your inheritance tree goes).
You can try defining an object hierarchy, and observe the effects from the execution of the constructors yourself. Here's a contrived example:
#include <iostream>
struct A
{
A(int nValue) {
std::cout << "A: " << nValue << std::endl;
}
};
struct B: public A
{
B(int nValue, double dValue)
: A(nValue) {
std::cout << "B: " << dValue << std::endl;
}
};
struct C: public B
{
C(int nValue, double dValue, char chValue)
: B(nValue, dValue) {
std::cout << "C: " << chValue << std::endl;
}
};
int main()
{
C cClass(5, 4.3, 'R');
return 0;
}
Can you imagine more complex hierarchies? What happens with other kinds of constructors? What about destructors?
A derived class is a class which inherits from another class. I suppose you're familiar with inheritance,somewhat. The derived class inherits the constructor of the base class, you just have to "override" it. So when you instantiate an object from the derived class, first the constructor of the base class is called and then the constructor of the derived class.
To instantiate something you create an instance of it:
instantiate
...
(transitive) To represent (something) by a concrete instance.
In class-based languages like C++ you have classes, which acts as blueprints, and then you have objects which are instances of specific classes.
For example, lets say you have a class A. If you then declare an object a of the class A then you instantiate an object of the class A.

C++ Method overloading by Inherited Parameter Type

If I have a Base and a Derived Class:
class Base {
//...
};
class Derived : public Base {
//...
};
Is it possible to overload functions in the following way?
void DoSomething(Base b) {
cout << "Do Something to Base" << endl;
}
void DoSomething(Derived d) {
cout << "Do Something to Derived" << endl;
}
What happens if I do this:
int main() {
Derived d = Derived();
DoSomething(d);
}
Derived is also a Base.. so which version gets called?
Yes, C++ lets you overload functions for base and derived classes. In fact, this mechanism is used by the standard library <algorithm> functions to select the correct algorithm depending on the types of the iterators passed in.
A Derived object is also a Base, but DoSomething(Derived) is an exact match, so it's preferred. DoSomething(d) will call DoSomething(Derived).
However, note that you can't get polymorphic behaviour this way. That is, if you have a Base& that actually refers to a Derived object, it still calls DoSomething(Base): that is, it dispatches on the static type. (In fact, since you are passing by value, it copies out only the Base part of the object into the parameter.) To get polymorphic behaviour, you would have to make DoSomething into a virtual member function (or make DoSomething(Base& b) call a virtual member function on b.)
The derived function will be called and used because it matches this "DoSomething(Derived d)"
signature.
Have you consider using the code like this instead:
#include<iostream>
using namespace std;
class Base {
public:
virtual void DoSomething();
};
class Derived : public Base {
public:
void DoSomething() override;
};
void Base:: DoSomething() {
cout << "Do Something to Base" << endl;
}
void Derived :: DoSomething() {
cout << "Do Something to Derived" << endl;
}
int main() {
Base *d = new Derived();
d->DoSomething();
delete d;
return 0;
}
It accomplished the same task, and allows you to take advantage of polymorphisms strength.