一、构造函数在继承中的注意点
1.引入
#include <iostream>
using namespace std;
class A {
public:
A() {
cout << this << "父类A的 无参数构造函数被调用\n";
}
};
class B : public A {
public:
B() {
cout << this << "父类B的 无参数构造函数被调用\n";
}
};
int main(int argc, char **argv) {
B obj_1;
return 0;
}
//
为什么父类A中的构造函数被调用呢?
如果父类有private修饰的成员变量,在子类中是无法使用,也就是意味着子类不能够对这些private成员变量进行初始化,因此就需要调用父类的构造函数
//
因此:
创建子类对象时,程序首先调用父类的构造函数,然后再调用子类的构造函数
父类构造函数负责初始化继承的数据成员
子类构造函数主要用于初始化新增的数据成员
子类构造函数总是需要调用一个父类构造函数;当父类没有无参数的构造函数时,就必须显式指明调用哪一个构造函数
2.默认调用父类无参构造函数
#include <iostream>
using namespace std;
class A {
public:
A() {
cout << this << "父类A的 无参数构造函数被调用\n";
}
A(int temp) {
cout << this << "父类A的 有参数构造函数被调用\n";
}
};
class B : public A {
public:
B() {
cout << this << "父类B的 无参数构造函数被调用\n";
}
B(int temp) {
cout << this << "父类B的 有参数构造函数被调用\n";
}
};
int main(int argc, char **argv) {
B obj_1;
cout << "---------------\n";
B obj_2(11);
return 0;
}
当父类有无参构造函数,在自动调用 子类构造函数 之前,一定会 先 自动调用父类的无参构造函数
3.父类没有无参构造函数,那么子类必须指定
#include <iostream>
using namespace std;
class A {
public:
// A() {
// cout << this << "父类A的 无参数构造函数被调用\n";
// }
A(int temp) {
cout << this << "父类A的 有参数构造函数被调用\n";
}
};
class B : public A {
public:
B() {
cout << this << "父类B的 无参数构造函数被调用\n";
}
B(int temp) {
cout << this << "父类B的 有参数构造函数被调用\n";
}
};
int main(int argc, char **argv) {
B obj_1;
cout << "---------------\n";
B obj_2(11);
return 0;
}
子类构造函数中怎样指定调用父类的哪个构造函数?
初始化列表
二、初始化列表
是在构造函数中,一种特殊写法的对成员变量初始化的方式
#include <iostream>
using namespace std;
class Person {
public:
int age;
char *address;
// // 这是普通的写法
// Person(int age, char *address) {
// this->age = age;
// this->address = address;
// }
// 使用初始化列表,对成员变量进行设置默认值
Person(int age, char *address): age(age), address(address){
}
};
int main(int argc, char **argv) {
// 创建对象
Person boy(33, "m78");
// 获取对象的成员变量
cout << boy.age << " " << boy.address << "\n";
return 0;
}
调用父类的构造函数
#include <iostream>
using namespace std;
// 父类
class People {
public:
char *name;
int age;
People(char *name, int age) {
this->name = name;
this->age = age;
}
virtual void display() {
cout << this->name << "今年" << this->age << "岁了,是个自由从业者" << endl;
}
};
// 子类
class Teacher : public People {
public:
int salary;
Teacher(char *name, int age, int salary) : People(name, age) {
this->salary = salary;
}
void display() {
cout << this->name << "今年" << this->age << "岁了,是一名教师,每月有" << this->salary << "元的收入" << endl;
}
};
int main() {
People *boy = new People("小明", 23);
boy->display();
People *girl = new Teacher("菲菲", 35, 8200);
girl->display();
return 0;
}
注意:成员变量的初始化顺序与初始化列表中列出的变量的顺序无关,它只与成员变量在类中定义的先后顺序有关
#include <iostream>
using namespace std;
class Demo {
public:
int m_a;
int m_b;
Demo(int b) : m_b(b), m_a(m_b) {
}
void show() {
cout << this->m_a << ", " << this->m_b << endl;
}
};
int main() {
Demo obj(100);
obj.show();
return 0;
}
在这段代码中:
定义了一个名为 Demo 的类,其中有两个 int 类型的成员变量 m_a 和 m_b 。
构造函数 Demo(int b) 接受一个参数 b ,用于初始化成员变量 m_b ,并通过 m_a(m_b) 尝试初始化 m_a 。
需要注意的是,在初始化列表中 m_a(m_b) 的这种初始化方式是不正确的。C++ 中,成员变量的初始化顺序是按照它们在类中的声明顺序进行的,而不是按照初始化列表中的顺序。所以在这里,m_a 会先被初始化(使用默认值),然后再执行 m_a(m_b) ,但这并不是对 m_a 的初始化操作,可能会导致未定义的行为。
在 main 函数中,创建了一个 Demo 类的对象 obj 并传递 100 给构造函数,然后调用 show 方法输出 m_a 和 m_b 的值。由于前面提到的初始化问题,m_a 的值可能不是预期的。
多继承中怎么用?
#include <iostream>
using namespace std;
class A {
public:
A(int num) {
cout << "A::A(int num), num=" << num << ", this=" << this << "\n";
}
};
class B {
public:
B(int num) {
cout << "B::B(int num), num=" << num << ", this=" << this << "\n";
}
};
class C : public A, public B { // 这里的继承循序 决定了初始化列表调用父类的构造函数的顺序
public:
C() : B(200), A(100) {
cout << "C::C(), this=" << this << "\n";
}
C(int num) : A(num), B(num + num) {
cout << "C::C(int num)\n";
}
};
int main() {
class C boy;
cout << "------------------------\n";
class C girl;
return 0;
}