I understand that when you inherit a parent class, the constructor of the child class should call the parent class constructor and that it shouldn’t just initialize the members that the parent class is supposed to initialize. It’s still acceptable to have the child constructor initialize/ set values for parent class members that aren’t touched in the parent class constructor right?
#Inheritance rules
24 messages · Page 1 of 1 (latest)
When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
generally you want a constructor to initialize all the members, so there shouldn't really be any members in the parent class that aren't touched by the constructor
that being said, it can be fine to just not call a constructor and initialize the members yourself in the base class, though that means that the base class members need to be protected or public
you should try to not build deep inheritance trees, ideally your base classes are all "interfaces" in the sense that they don't contain any nonstatic member variables
Technically you cannot initialize members of the base class in the derived class' constructor. By the time the derived class' constructor runs, the base class' constructor already ran and created all the members. All you can do now is overwrite their values.
Overwriting the members of the base class is a reasonable thing to do for a derived class, but you should probably use a constructor of the base class for that so you can directly initialize those variables instead of constructing them with the wrong value and overwriting it after. Maybe the compiler can fix that, maybe not, but it's just cleaner to give things the right value from the start.
yeah I guess what I said was really misleading
I meant something like ```c++
struct Base {
int x;
int y;
};
// ...
Derived::Derived(int x, int y): Base {x, y}
where you haven't written a `Base` constructor yourself
when an object of the child class is created, the child class will always initialize the base class with or without you giving it the data to initialize. If not given, it'll be initialized with default value which later you can overwrite in your child class, as Toeger said, which costs additional time unnecessarily while you can give it the data to initialize at the start, I want you to remember that, the base class is initialized before the child class, even when you're creating the object of the child class
;compile ```cpp
#include <iostream>
class Base {
public:
int a;
Base(int x = 10) : a(x) {
std::cout << "Base construct" << std::endl;
}
};
class Der : public Base {
public:
Der() {
std::cout << "Der construct" << std::endl;
}
void print() {
std::cout << a;
}
} ;
int main() {
Der D;
D.print();
return 0;
}
Program Output
Base construct
Der construct
10
micebear | 46ms | c++ | x86-64 gcc 15.1 | godbolt.org
now compare the asm of the code
;asm ```cpp
#include <iostream>
class Base {
public:
int a;
Base(int x = 10) : a(x) {
std::cout << "Base construct" << std::endl;
}
};
class Der : public Base {
public:
Der() {
std::cout << "Der construct" << std::endl;
}
void print() {
std::cout << a;
}
} ;
int main() {
Der D;
D.print();
return 0;
}
Assembly Output Pt. 1
.LC0:
.string "Base construct"
Base::Base(int) [base object constructor]:
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov DWORD PTR [rbp-12], esi
mov rax, QWORD PTR [rbp-8]
mov edx, DWORD PTR [rbp-12]
mov DWORD PTR [rax], edx
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:std::cout
call std::basic_ostream<char, std::char_traits<char>>& std::operator<<<std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&, char const*)
mov esi, OFFSET FLAT:std::basic_ostream<char, std::char_traits<char>>& std::endl<char, std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&)
mov rdi, rax
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
nop
leave
ret
.LC1:
.string "Der construct"
Der::Der() [base object constructor]:
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov esi, 10
mov rdi, rax
call Base::Base(int) [base object constructor]
Assembly Output Pt. 2
mov esi, OFFSET FLAT:.LC1
mov edi, OFFSET FLAT:std::cout
call std::basic_ostream<char, std::char_traits<char>>& std::operator<<<std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&, char const*)
mov esi, OFFSET FLAT:std::basic_ostream<char, std::char_traits<char>>& std::endl<char, std::char_traits<char>>(std::basic_ostream<char, std::char_traits<char>>&)
mov rdi, rax
call std::ostream::operator<<(std::ostream& (*)(std::ostream&))
nop
leave
ret
Der::print():
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
mov esi, eax
mov edi, OFFSET FLAT:std::cout
call std::ostream::operator<<(int)
nop
leave
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
lea rax, [rbp-4]
mov rdi, rax
call Der::Der() [complete object constructor]
lea rax, [rbp-4]
mov rdi, rax
call Der::print()
mov eax, 0
leave
ret
micebear | 461ms | c++ | x86-64 gcc 15.1 | godbolt.org
in the .LC1 text segment, you can see this line where it calls
call Base::Base(int)
before the std::ostream call which is std::cout
so you can't do anything about that unless you hide the base class' constructor but you can't do that either
if you hide the base class' constructor, this is what happens
;compile ```cpp
#include <iostream>
class Base {
public:
int a;
private:
Base(int x = 10) : a(x) {
std::cout << "Base construct" << std::endl;
}
};
class Der : Base {
public:
Der() {
std::cout << "Der construct" << std::endl;
}
void print() {
std::cout << a;
}
} ;
int main() {
Der D;
D.print();
return 0;
}
Compiler Output
<source>: In constructor 'Der::Der()':
<source>:13:15: error: 'Base::Base(int)' is private within this context
13 | Der() {
| ^
<source>:6:9: note: declared private here
6 | Base(int x = 10) : a(x) {
| ^~~~
Build failed
micebear | c++ | x86-64 gcc 15.1 | godbolt.org