Suppose you wanted to reproduce the following Python snippet:
class Base:
name = "base"
def announce(self):
print(self.name)
class Derived(Base):
name = "derived"
Base().announce()
Derived().announce()
... which would output:
"base"
"derived"
Initially, you may be inclined to write something like the following:
#include <iostream>
#include <string>
struct Base {
std::string name = "base";
void announce() {
std::cout << name << std::endl;
}
};
struct Derived : public Base {
std::string name = "movie";
};
int main() {
Base().announce();
Derived().announce();
return 0;
}
But here Derived.name simply shadows Base.name. Calling Derived.announce() references Base.name and prints "base".
Is there any way to implement this behaviour? Ideally without class templates if possible.
C++ doesn't work like Python (which isn't surprising, they are two very different languages after all), and member variables defined in an inherited class really defines a new variable that is unrelated to the variables of the parent class.
One possible solution is to create a second (possibly protected) Base constructor which takes the name as an argument, and then the Derived class can use it to initialize the member:
struct Base {
Base() = default; // A defaulted default constructor
std::string name = "base";
void announce() {
std::cout << name << std::endl;
}
protected:
explicit Base(std::string name)
: name{ std::move(name) } // Initialize the member
{
}
};
struct Derived : public Base {
Derived()
: Base("movie") // Initialize the base class using the special constructor
{
}
};
The default Base default constructor is needed, because if you declare another constructor the compiler won't automatically generate a default constructor for you.
Related
I'm getting started with class inheritance in c++ and I'm really stuck.
From the child class I'm trying to call the parent constructor and pass a variable as a parameter. The warning says field 'default_name' is uninitialized when used here [-Wuninitialized].
class ParentClass {
public:
ParentClass(std::string _name): name(_name) {};
std::string name;
void printname() {
std::cout << this->name << std::endl;
}
}
class DerivedClass: public ParentClass {
public:
std::string default_name = "Alex";
DerivedClass(): ParentClass(default_name) {};
}
This obviously does not work because DerivedClass() is going to be called before default_nameis even initialized. Is there a way to construct an object of the parent class from the derived class using a variable?
Parent classes are constructed first. Even though, in your program, your initialization of name appears first, that doesn't mean anything. C++ has strict construction and initialization rules. You are attempting to construct the parent class before name gets initialised.
name gets constructed after the parent class gets constructed.
So what you can do is to move name into another parent class before the existing one. That one gets constructed first, then your existing constructor will have an initialized member, to work with..
Members are always initialized in the same order: First base class sub-objects, then members in the order they are listed in the class declaration. Hence, your usage of a default initializer is more or less the same as:
class DerivedClass: public ParentClass {
public:
std::string default_name;
DerivedClass(): ParentClass(default_name),default_name("Alex") {};
}
Now it is more obvious that default_name is passed to the constructor of ParentClass before it is initialized. I think you already knew that... to fix it you have several options. As the default_name seems to be attached to the DerivedClass rather than instances of the class, you can make it static:
#include <string>
#include <iostream>
class ParentClass {
public:
ParentClass(std::string _name): name(_name) {};
std::string name;
void printname() {
std::cout << name;
}
};
class DerivedClass: public ParentClass {
public:
static const std::string default_name;
DerivedClass(): ParentClass(default_name) {};
};
const std::string DerivedClass::default_name = "Alex";
int main(){
DerivedClass{}.printname();
}
A base class has to be initialized before the current class members, hence the error. Here, you could make default_name static. That way it would be available at object construction time:
class DerivedClass: public ParentClass {
public:
static std::string default_name;
DerivedClass(): ParentClass(default_name) {};
};
std::string DerivedClass::default_name = "Alex";
Here, default_name could (should?) be const.But in fact, it would be even simpler to use a literal string here:
class DerivedClass: public ParentClass {
public:
DerivedClass(): ParentClass("Alex") {};
};
I come from a Python background, and currently I'm learning OOP in C++.
I'm having problems figuring out how to get the code to call the correct method in a helper class HelperBase that is inherited to HelperChild.
#include <iostream>
class HelperBase {
public:
HelperBase() {}
virtual void something() {
std::cout << "HelperBase" << std::endl;
}
};
class HelperChild : public HelperBase {
public:
HelperChild() {}
void something() {
std::cout << "HelperChild" << std::endl;
}
};
The HelperBase class i used in the class Base, where it is set as a member variable.
class Base {
public:
Base(HelperBase &helperBase) : hb(helperBase) {}
virtual void print() {
std::cout << "-- Base" << std::endl;
hb.something();
}
HelperBase hb;
};
Then this class is used as the base class of the class Child:
class Child : public Base {
public:
Child(HelperChild &helperChild) : Base(helperChild) {
helperChild.something();
}
};
The main method is
int main() {
HelperChild helperChild;
Child child(helperChild);
child.print();
return 0;
}
This outputs the following:
HelperChild
-- Base
HelperBase
Why isn't the 'HelperChild' printed in the last line? What changes do I have to do to achieve this? (I'm not sure if I have used virtual in the correct way).
EDIT: In the actual case im trying to figure out, Base::print is a really large method that I don't want to override in the Child class. I just want to change the behaviour of the helper class.
Copy constructor will NOT copy derived object, it will get sliced and create a base object.
To elaborate, you may consider copy constructor as "copy by value", every value of derived object would be copied to create a base object. Since your Helper classes have no class members, it copied nothing.
Also function is not copyable, C++ handles virtual functions by vtable. A base class would have a vtable of base class, that's why hb.something() called the base version.
Last line is printing Helper base because your Base has a HelperBase but not a derived HelperChild.
class Base {
public:
Base(HelperBase &helperBase) : hb(helperBase) {} // hp(helperBase) means you still have a helper base.
virtual void print() {
std::cout << "-- Base" << std::endl;
hb.something();
}
HelperBase hb;
};
Then in main, child.print() will call the hb.something() which belongs to HelperBase.
To achieve polymorphism, you need a pointer to take the instance of HelperChild. It's called Dependency Injection and I assumed you were trying to achieve it.
class Base {
public:
Base(HelperBase &helperBase) {
hb = &helperBase;
}
virtual void print() {
std::cout << "-- Base" << std::endl;
hb->something();
}
HelperBase* hb;
};
The HelperBase hb in class Base is always of type HelperBase - even if you call print from an instance of type Child.
There are various ways to achieve what you want. One option is to use PIMPL to store a pointer to a Helper class. A different option is to use CRTP.
I am trying to create a derived class object and populate the data-members (coming from base class) with a existing base class object.
In my process lifecycle, I already had a base class object. For some decision, I have to create a new object (derived from base class). One way to do this is expose the assessors and copy the data. Is there any solution like aggregate initialization or dynamic_cast that I could use instead?
#include <iostream>
#include <string>
using namespace std;
class Base {
protected:
string name_;
public:
Base() : name_ ("foo")
{
}
void ChangeName()
{
name_ = std::string {"bar"};
}
};
class Child final : Base {
public:
string GetName()
{
return name_;
}
};
int main()
{
Base b;
b.ChangeName();
Child c = {b};
cout<<"Hello World. Here is my name: " << c.GetName() << endl;
return 0;
}
Expected Output:
Hello World. Here is my name: bar
Compilation Error
try.cpp:33:17: error: could not convert ‘{b}’ from ‘<brace-enclosed initializer list>’ to ‘Child’
Child c = {b};
If you want to construct a Child from a Base, you need to add a constructor to Child that will do that:
Child(const Base &b): Base(b) { }
You need to be cautious using this, as it will allow constructing a Child from another class that is also derived from Base. And if Child has any other data members, you need to be sure to add appropriate initialization or default values for them.
Something like this is possible using the C-style casts:
Child c(*(Child*)&b);
But I wouldn't advise you to use this. It can fail if the memory layouts of the classes aren't similar. The equivalent C++ cast for this situation is this:
Child c(*reinterpret_cast<Child*>(&b));
EDIT: Turns out this is Undefined Behavior. Don't attempt this :)
Could anybody explain where c++ compilers keep default values for parameters for virtual functions? I know it is a bad idea to change these parameters in child classes but why?
Thanks.
It's a bad idea because they aren't kept anywhere.
The default values that are used will be those defined in the static (compile-time) type. So if you were to change the default parameters in an override, but you called the function through a base class pointer or reference, the default values in the base would be used.
#include <iostream>
struct Base
{
virtual ~Base(){ }
virtual void foo(int a=0) { std::cout << "base: " << a << std::endl; }
};
struct Derived : public Base
{
virtual ~Derived() { }
virtual void foo(int a=1) { std::cout << "derived: " << a << std::endl; }
};
int main()
{
Base* derived = new Derived();
derived->foo(); // prints "derived: 0"
delete derived;
}
Giving virtual functions default argument initializers tends to defeat polymorphism and introduce unnecessary complexity into a class hierarchy.
consider the following non compliant code
class Thing {
public:
virtual ~Thing();
virtual void doItNTimes( int numTimes = 10 );
virtual void doItThisHigh( double howHigh = 1.0 );
// ...
};
class MyThing : public Thing {
public:
void doItNTimes( int numTimes );
void doItThisHigh( double howHigh = 2.2 );
// ...
};
A default initializer is not part of the type of a function signature and does not participate in overriding or hiding. Therefore both of the base class virtual functions shown in this Non-Compliant Code Example are overridden in the derived class. However, the differences in the status of default argument initializers in the base class and derived class interfaces causes differences in behavior depending on which interface is used to access an object.
MyThing *mt = new MyThing;
Thing *t = mt;
t->doItNTimes(); // default of 10
mt->doItNTimes(); // compile time error!
t->doItThisHigh(); // default of 1.0!
mt->doItThisHigh(); // default of 2.2
In this piece of code, the intention of the designer of the MyThing class is not clear. Presumably, it is important that the default value to doItThisHigh for an object of type MyThing be 2.2. However, it is not clear whether that value should also be used by default when a MyThing is manipulated through its Thing interface.
For more details Please refer the below link https://www.securecoding.cert.org/confluence/display/cplusplus/OOP04-CPP.+Prefer+not+to+give+virtual+functions+default+argument+initializers
#include <fstream>
using namespace std;
ofstream out("order.out");
#define CLASS(ID) class ID { \
public: \
ID(int) { out << #ID " constructor\n"; } \
~ID() { out << #ID " destructor\n"; } \
};
CLASS(Base1);
CLASS(Member1);
CLASS(Member2);
CLASS(Member3);
CLASS(Member4);
class Derived1 : public Base1 {
Member1 m1;
Member2 m2;
public:
Derived1(int) : m2(1), m1(2), Base1(3) {
out << "Derived1 constructor\n";
}
~Derived1() {
out << "Derived1 destructor\n";
}
};
class Derived2 : public Derived1 {
Member3 m3;
Member4 m4;
public:
Derived2() : m3(1), Derived1(2), m4(3) {
out << "Derived2 constructor\n";
}
~Derived2() {
out << "Derived2 destructor\n";
}
};
int main() {
Derived2 d2;
}
"Note that the
constructors are not default constructors; they each have an int
argument. The argument itself has no identifier; its only reason for
existence is to force you to explicitly call the constructors in the
initializer list"
As the classes have a user-defined constructor and that user-defined
constructor is not the default constructor, there is no default
constructor available in those classes.
This makes it necessary to explicitly mention one of the available
constructors in the member initializer list of a derived class.
class Derived : public Base {
Derived() {} // fails to compile, no constructor Base::Base() available
Derived() : Base(3) {} // works
};
So much for what the code does and how it achieves it. I have no idea
why you should ever need something like that, but you never know.
What it means that the argument has no identifier - no name - and thus it is not used anywhere in the constructor.
But, when you make an object that belongs to the derived class, it's constructor calls the constructor of the parent class. Also, when you have an object member, you have to initialize it in your constructor.
If the parent class had a default (no-arguments) constructor, you would not have to call it at all - it would have been done automatically. Also, if you do not initialize the object member, it will be done automatically via the default constructor.
Since none of your classes actually have a default constructor, you have to explicitly call the parent class constructor, and also initialize members via their only existing constructor with one argument.
Using the unnamed argument in all the classes does just that - forces you to explicitly call their constructors, instead of just relying on the default constructor being called.
Providing a constructor that takes an argument prevents the compiler from synthesising a default constructor. This forces the user of the ID class to provide an int, which is discarded, when creating an instance of this class. I can see no practical application of this approach.
To simplify this demonstration code:
#include <iostream>
struct ID
{
ID(int)
{
std::cout << "ID constructor" << std::endl;
}
};
int main()
{
ID this_will_compile(0);
ID this_will_not_compile;
}
While the first creation of an instance of ID will succeed, the second attempt will fail. You compiler will tell you something like:
error: no matching function for call to ‘ID::ID()’
The same is true for deriving from such a class:
This will work...
struct DerivedWorking: public ID
{
DerivedWorking()
:ID(0)
{
}
};
Whereas this will not, because it doesn't provide an int to ID's constructor...
struct DerivedBroken: public ID
{
DerivedBroken()
{
}
};