Trying to use a virtual function in my initialization list - c++

I am trying to create a base and a derived class with a const member that has to be initialized:
class baseClan
{
public:
baseClan(const string firstName)
:
fullName(createFullName(firstName))
{}
private:
const string lastName = "Smith";
const string fullName;
virtual const string createFullName(string firstName) { return firstName + " " + lastName ; }
}
How do I implement the derived class so that it can use a differently implemented createFullName? I am looking at this link
https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom
but it seems like I'm stuck between a rock and a hard place: the first approach it proposes (using init) is not applicable to initialization list; while in the second approach it is explicitly stated that it cannot handle the case where we need to access the instance data declared in Derived.

Calling virtual functions from a constructor or destructor is dangerous and should be avoided whenever possible. All C++ implementations should call the version of the function defined at the level of the hierarchy in the current constructor and no further.
Virtual functions in the constructors work differently. When creating an object of an derived class, the object of the base class is created first, which means that the derived class has not yet been created and the virtual function has not yet been overrided.
I think that all possible approaches to this problem are already described by the link that you provided (C++ FAQ). But I highly recommend rethinking your code.
You can apply a slightly different approach. You can make base constructor to accept parameters to initialize data fields, and then in derived class you pass the necessary arguments (even, perhaps, from virtual functions) to the base constructor using the initialization list. For example:
class A {
public:
A(int a, int b) : a_(a), b_(b) { }
virtual int getA() const = 0;
virtual int getB() const = 0;
void print() { cout << a_ << ' ' << b_ << endl; }
private:
const int a_ = 0;
const int b_ = 0;
};
class B : public A {
public:
B() : A(getA(), getB()) { }
int getA() const override { return 1; }
int getB() const override { return 2; }
};
int main() {
B b;
b.print();
return 0;
}

Related

How to access inherited class attribute from a third class?

The goal of the code structure below is to be able to store pointers to objects of any class inherited from 'A'.
When I run this code, I get 0 written out, but what I'm trying to access is the 'B' object's 'num' value, which is 1. How can I do that?
As far as I know, when you create an inherited class's object, you create an object of the parent class too automatically. So can I somehow access the parent class object from it's child and set it's class member to match?
See minimal reproducible example below.
Update: Virtual functions solved the problem.
#include <iostream>
class A
{
public:
int num;
A()
{
num = 0;
}
};
class B : public A
{
public:
int num;
B()
{
num = 1;
}
};
class C
{
public:
A* ptr_array[2];
C()
{
ptr_array[0] = new B();
}
void print()
{
std::cout << ptr_array[0]->num << std::endl;
}
};
int main()
{
C* object_c = new C();
object_c->print();
return 0;
}
The problem is that you define a member num in A, and another member num in B. So an object of type B has two members called num, and you're leaving it to the compiler to choose which one to use -- which it does, according to logical rules which may be unfamiliar to you.
If you remove the line in num; from the definition of B, the code will work as you intend.
Your array is a red herring. You are only using one pointer. Might just as well have it as a member for the sake of the example.
I suppose you might need something like this (note, untested code).
#include <memory>
#include <iostream>
class A {
public:
A() : m_num(0) {} // use this instead of assignment in the c'tor body
virtual int getNum() { return m_num; } // this is **the** way to use inheritance
virtual ~A() = default; // required
private:
int m_num;
};
class B : public A {
public:
B() : m_otherNum(1) {}
virtual int getNum() { return m_otherNum; } // does something different from A
private:
int m_otherNum; // you could also call it m_num, but for clarity I use a different name
};
class C {
public:
C() : m_a (std::make_unique<B>()) {} // note, use this instead of new B
void print() {
std::cout << m_a->getNum() << std::endl;
}
private:
std::unique_ptr<A> m_a; // note, use this instead of A* m_a;
};
I have no way of knowing if this is really what you need (or you think you need). This is how inheritance is supposed to be used in object-oriented programming. You can use it in various other ways and produce correct (as far as the language definition is concerned) programs. But if this is the case, then (public) inheritance is likely not the best tool for the job.

Manually calling constructor of base class outside initialization list

I have a Derived class whose constructor has to populate the fields of a struct that is passed as an argument to the constructor of the Base class. I want to be able to name the fields of the struct that I am populating, to keep my code future-proof (i.e.: resistant to addition and/or reordering of the members of MyStruct).
Note that struct MyStruct has default values, so it cannot be initialised with named fields directly in the initialization list (e.g.: Base({.a = a, .b = b}) does not work). Also, in my case, Base's copy constructor is deleted. Also, I am using C++ 11.
The solution I came up with uses the placement new operator to manually call the constructor of the Base class on the memory pointed to by this. To achieve this I also had to add a protected default constructor to my Base class. Are there any possible downsides to this approach and/or could anyone suggest a better method?
#include <iostream>
struct MyStruct
{
int a = 0;
int b = 1;
};
class Base
{
public:
Base(MyStruct str){
std::cout << "a: " << str.a << ", b: " << str.b << "\n";
}
Base(Base&&) = delete; // no copy constructor
protected:
Base(){ // dummy, does exactly nothing.
// it only exists to be called by
// the derived class's constructor
}
private:
int amember;
};
class Derived : public Base
{
public:
Derived(int a, int b)
{
MyStruct str;
str.a = a;
str.b = b;
new (this) Base(str);
}
private:
int anothermember;
};
int main()
{
MyStruct str;
str.a = 10;
str.b = 20;
Base b(str);
Derived d(10, 20);
return 0;
}
edit: added mention that Base cannot be copied, made explicit that Base::Base() does exactly nothing.
Use a helper function instead like
class Derived : public Base
{
public:
Derived(int a, int b) : Base(make_mystruct(a, b)), anothermember(some_value) {}
private:
int anothermember;
static MyStruct make_mystruct(int a, int b) { return MyStruct(a, b); }
};
I would just like to add that this could be a good opportunity to use IILE, Immediately Invoked Lambda Expression, if you for whatever reason don't want a named helper function:
class Derived : public Base
{
public:
Derived(int a, int b) : Base{[](){
MyStruct str;
str.a = a;
str.b = b;
return str; }()}
{}
};
The benefit is that you will not need to construct the class and it's members only once, since you do everything in the initialization list. If you in the future add non-trivial members to Base, you will be will not have to pay for double initialization.

Call overload function based on child in parent container

I'd like to store a child object in a container of its parent type, and then call a function overload based on the type of child in the container. Is that possible?
#include <vector>
class Parent { public: };
class A : public Parent { public: };
class B : public Parent { public: };
class C : public Parent { public: };
class Hander
{
public:
static void handle(A & a) {}
static void handle(B & b) {}
static void handle(C & c) {}
};
int main()
{
A test1;
Hander::handle(test1); // compiles and calls the correct overload
Parent test2 = A();
Hander::handle(test2); // doesn't compile
Parent * test3 = new A();
Hander::handle(*test3); // doesn't compile
Parent children1[] = { A(), B(), C() };
for (int i = 0; i < 3; ++i)
Hander::handle(children1[i]); // doesn't compile
std::vector<Parent*> children2 = { new A(), new B(), new C() };
for (int i = 0; i < 3; ++i)
Hander::handle(*children2[i]); // doesn't compile
}
No, it is not possible.
The function which is called is chosen at compile-time. Lets say you have code like this:
Base &o = getSomeObject();
handle(o);
The compiler doesn't know the real type of o. It only knows that it is some subtype of Base or Base itself. This mean it will search for a function which acceppts objects of type Base.
You could implement a check for the type yourself or use a map to store possible functions:
Base &o = getSomeObject();
functionMap[typeid(o)](o);
But typeid does only work this whay if Base is a polymorphic type. This mean it must have at least one virtual function. This brings us to the next section:
But you could use virtual functions.
Virtual functions are non-static member functions of classes which can be overridden. The right function is resolved at runtime. The following code would output Subt instead of Base:
class Base {
public: virtual std::string f() {return "Base"}
};
class Subt : public Base {
public: virtual std::string f() {return "Subt"}
};
int main() {
Subt s;
Base &b = s;
std::cout << b.f() << std::endl;
}
You can omit virtual in the definition of Subt. The function f() is already defined as virtual in it's base class.
Classes with at least one virtual function (also called polymorphic types) are storing a reference to a virtual function table (also called vtable). This table is used to get the right function at runtime.
The problem in your question could be solved like this:
class Parent {
public:
virtual void handle() = 0;
};
class A : public Parent {
public:
void handle() override { /* do something for instances of A */ }
};
class B : public Parent {
public:
void handle() override { /* do something for instances of B */ }
};
class C : public Parent {
public:
void handle() override { /* do something for instances of C */ }
};
int main()
{
std::vector<std::unique_ptr<Parent>> children = {
std::make_unique<A>(),
std::make_unique<B>(),
std::make_unique<C>()};
for (const auto &child : children)
child->handle();
}
Note about compatibility: The keywords auto and override are only available in C++11 and above. The range-based for loop and std::unique_ptr is also available since C++11. The function std::make_unique is available since C++14. But virtual function can be used with older versions, too.
Another hint:
Polymorphism does only work with references and pointers. The following would call Base::f() and not Subt::f():
Subt s;
Base b = s;
std::cout << b.f() << std::endl;
In this example b will just contain a object of type Base instead of Subt. The object is just created at Base b = s;. It may copy some information from s but it isn't s anymore. It is a new object of type Base.

When protected protects too much

This is about "protected", which is explained as: "When a class inherits another one, the members of the derived class can access the protected members inherited from the base class." However, look at this code:
class Base {
public:
Base( int m ) : member(m){}
protected:
int member;
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int diff( Base x ){
return value - x.member;
}
private:
int value;
};
Derived accesses "x.member", which is protected in its Base class, right? But the compiler flags an error, "Base::member is protected". And, after mulling this over for a minute, I had to agree with the compiler.
And here comes the question: How do I make this work, with a minimum loss of information hiding?
Clearly, making "member" public compiles, but it's against the original intent.
Using the "friend" mechanism in Base to let subclasses access "member" (and everything else that's private and protected) is even worse (apart from the dumb binding of a superclass to its own subclasses - a maintenance nightmare).
In the simple example, a public int getMember(){ return member; } would be acceptable. But if member's type is a X*, the best you can do is a public const X* getMember(){...}.
Did I miss something?
You can keep the protected attributes, add the getter functions as you mentioned. As for a protected pointer attribute, the getter would make sure that int (or a const ref for a large object) is returned and you can do the difference in a function template that takes Derived and Base arguments then (getters give you the values for the calculation).
Protecting data attributes allows direct access to the protected attribute within the derived class. What you tried is to access a private attribute of another object. This part of your code:
int diff( Base x ){
return value - x.member;
}
would be equivalent to writing this in main:
Base x;
cout << x.member << endl;
Here is an example of how to solve the problem using the option 3 you suggested yourself, with a derived class PointerDerived that is using pointers for the storage:
#include <iostream>
class Base {
public:
Base( int m ) : member(m){}
int getMember() const
{
return member;
}
protected:
int member;
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int getValue() const
{
std::cout << "protected = " << member << std::endl;
return value;
}
private:
int value;
};
class PointerDerived : public Base { // one of several subclasses
public:
PointerDerived( int m ) : Base(m), value(new int (10)) {}
int getValue() const
{
std::cout << "protected = " << member << std::endl;
return *value;
}
~PointerDerived()
{
delete value;
value = nullptr;
}
private:
int* value;
};
template<typename Derived, typename Base>
int diff(const Derived& d, const Base& b)
{
return d.getValue() - b.getMember();
}
using namespace std;
int main(int argc, const char *argv[])
{
PointerDerived p(23);
Base q(1);
cout << diff(p, q) << endl;
return 0;
}
Compile the program with -std=c++11 because of the nullptr, or change it to NULL.
You make the diff a function template, so that you don't have to overload it for each and every derived class, and you let the derived class handle the storage and access to it as does for example PointerDerived.
You can use a static protected accessor:
class Base {
public:
Base( int m ) : member(m){}
private:
int member;
protected:
static int GetMember(const Base &b)
{ return b.member; }
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int diff( Base &x ){ //beware of your slicing!
return value - GetMember(x);
}
private:
int value;
};
Now let me add my idea of why C++ access control works this way...
Access control in C++ is not about information hiding. It is about encapsulation. That is, plainly speaking, you filter out the access to any member that can break the class if used incorrectly.
In an ideal class
public members cannot be used to break the object.
private members know what they are doing.
As you see, in my scheme there is little place for protected members:
protected members are used to implement the inheritance interface, if any.
And even less place for protected member variables.
So make your variable private, and write a protected accessor. The accessor must be static to be able to be used from the derived object.

Implement two functions with the same name but different, non-covariant return types due to multiple abstract base classes

If I have two abstract classes defining a pure virtual function with the same name, but different, non-covariant return types, how can I derive from these and define an implementation for both their functions?
#include <iostream>
class ITestA {
public:
virtual ~ITestA() {};
virtual float test() =0;
};
class ITestB {
public:
virtual ~ITestB() {};
virtual bool test() =0;
};
class C : public ITestA, public ITestB {
public:
/* Somehow implement ITestA::test and ITestB::test */
};
int main() {
ITestA *a = new C();
std::cout << a->test() << std::endl; // should print a float, like "3.14"
ITestB *b = dynamic_cast<ITestB *>(a);
if (b) {
std::cout << b->test() << std::endl; // should print "1" or "0"
}
delete(a);
return 0;
}
As long as I don't call C::test() directly there's nothing ambiguous, so I think that it should work somehow and I guess I just didn't find the right notation yet. Or is this impossible, if so: Why?
Okay, it is possible, and the way isn't too ugly. I have to add an additional level of inheritance:
ITestA ITestB <-- These are the interfaces C has to fulfill, both with test()
| |
ITestA_X ITestB_X <-- These classes implement the interface by calling a
| | function with a different name, like ITestA_test
\__________/ which is in turn pure virtual again.
|
C <-- C implements the new interfaces
Now C has no function test(), but when casting a C* to an ITestA*, the implementation of test() in ITestA_test will be used. When casting it to an ITestB*, even by a dynamic_cast from the ITestA*, the implementation of ITestB_test will be used.
The following program prints:
3.14
0
#include <iostream>
class ITestA {
public:
virtual ~ITestA() {};
virtual float test() =0;
};
class ITestB {
public:
virtual ~ITestB() {};
virtual bool test() =0;
};
class ITestA_X : public ITestA {
protected:
virtual float ITestA_test() =0;
virtual float test() {
return ITestA_test();
}
};
class ITestB_X : public ITestB {
protected:
virtual bool ITestB_test() =0;
virtual bool test() {
return ITestB_test();
}
};
class C : public ITestA_X, public ITestB_X {
private:
virtual float ITestA_test() {
return 3.14;
}
virtual bool ITestB_test() {
return false;
}
};
int main() {
ITestA *a = new C();
std::cout << a->test() << std::endl;
ITestB *b = dynamic_cast<ITestB *>(a);
if (b) {
std::cout << b->test() << std::endl;
}
delete(a);
return 0;
}
Does this have any drawbacks you could think of?
When you declare ITestA *a = new C(), you have created a C object. If you invoke test on it with a->test(), it has to use the C virtual table to find the code to execute. But C is trying to have two different implementations of the same signature test(), which isn't allowed. The fact that you declared it as an ITestA * doesn't affect the method resolution. You declared the methods virtual, so they are found via the actual type of the object, regardless of the type of the pointer you used to access it.
You cannot have two methods with the same name and argument types. You'll need to find another way to structure this code.
I don't think this is possible. Functions overload by name (and signature).