1.构造函数、拷贝构造、赋值重载、析构函数不能够被继承
一、缺省的构造函数
- 如果基类和派生类中没有给出构造函数,则C++编译器自动给出一个缺省的构造函数,C++编译器在派生类的构造函数的初始化列表中加入基类的缺省构造函数的调用。
主要目的:将对象创建出来
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
using namespace std;
class Person
{
private:
int idPerson;
public:
Person(){} //无参
void Dance()const
{
cout << "跳舞" << endl;
}
};
class Student :public Person
{
private:
int snum;
public:
Student():Person(){} //无参
void Study()const
{
cout << "学习" << endl;
}
};
- 基类有缺省构造函数,有程序设计者定义
- 程序设计者没有在派生类中定义构造函数
- C++编译器会在派生类自动产生派生类的缺省构造函数
- 在初始化表中加入基类的缺省构造函数的调用
class Person
{
private:
int idPerson;
public:
Person():idPerson(1){}
Person(int id):idPerson(id){} //带参构造函数
void Dance()const
{
cout << "跳舞" << endl;
}
};
class Student :public Person
{
private:
int snum;
public:
//Student():Person(){} //系统自己给出
void Study()const
{
cout << "学习" << endl;
}
};
- 派生类构造函数程序设计者定义
- 程序设计如果不在初始化列表中加入基类缺省的构造函数调用
- C++编译器将在初始化表中加入基类缺省构造函数
class Person
{
private:
int idPerson;
public:
Person():idPerson(1){}
Person(int id):idPerson(id){} //带参构造函数
void Dance()const
{
cout << "跳舞" << endl;
}
};
class Student :public Person
{
private:
int snum;
public:
Student(){} //没有在初始化列表中加入基类缺省的构造函数调用
//Student():Person(){} //系统自己给出
void Study()const
{
cout << "学习" << endl;
}
};
- 如果基类中没有给出无参的构造函数,只给出带参的构造函数,那么派生类无法合成相应的缺省函数进行调动
class Person
{
private:
int idPerson;
public:
//Person():idPerson(1){} //没有给出
Person(int id):idPerson(id){} //带参构造函数
void Dance()const
{
cout << "跳舞" << endl;
}
};
class Student :public Person
{
private:
int snum;
public:
//Student():Person(){} //error
Student():Person(1),snum(0){}
Student(int id,int s):Person(id),snum(s){}
void Study()const
{
cout << "学习" << endl;
}
};
二、缺省的拷贝构造函数
- 程序设计者在基类和派生类中都没有定义拷贝构造函数,C++编译器将自动产生按位拷贝的拷贝构造函数,在派生类的拷贝构造函数的初始化列表中,加入基类的拷贝构造函数的调用,是C++编译器合成的代码(基类、派生类都没有拷贝构造函数)
- 程序设计者在基类中定义拷贝构造,但是派生类没有拷贝构造,C++编译器将在派生类自动产生按位拷贝的拷贝构造函数(基类中有、派生类中没有)
- 程序设计者在基类派生类中都定义了拷贝构造函数,但是在派生类中没有调用基类的拷贝构造函数,C++编译器调用的是缺省构造函数,如果基类没有缺省构造,那合成代码失败。(基类,派生类都有拷贝构造函数)
- 程序设计者在派生类中定义了拷贝构造,基类中没有定义,没有指定调用基类的拷贝构造函数时,C++编译器将调用基类的缺省构造函数(基类中没有、派生类中有)
class Person
{
private:
int idPerson;
public:
//Person():idPerson(1){} //没有给出
Person(int id):idPerson(id){} //带参构造函数
Person(const Person& per):idPerson(per.idPerson)//拷贝构造
{
cout<<"Copy Person"<<endl;
}
void Dance()const
{
cout << "跳舞" << endl;
}
void PrintPerson()
{
cout<<"身份证号"<<idPerson<<endl;
}
};
class Student :public Person
{
private:
int snum;
public:
//Student():Person(){} //error
Student():Person(1),snum(0){}
Student(int id,int s):Person(id),snum(s){}
Student(const Student& stud):Person(stud),_sum(stud._snum)//拷贝构造
{
cout<<"Copy Student"<<endl;
}
void Study()const
{
cout << "学习" << endl;
}
void PrintStudent()
{
PrintPerson();
cout<<"学号"<<snum<<endl;
}
};
三、缺省的赋值重载
- 程序设计者在基类和派生类中都没有重载operator=函数,C++编译器将在基类和派生类中自动产生按位赋值重载的函数(0,0)
- 程序在基类中有赋值重载函数,在派生类没有赋值重载函数,C++编译会在派生类自动加入赋值重载语句(1,0)
- 程序在基类中有赋值函数,在派生类有赋值重在函数,如果在派生类没有指明调用基类的赋值重载函数,那么编译器不会合成基类的赋值重载函数。也就是只会赋值派生类的成员属性。(1,1)
- 程序在基类中没有赋值函数,在派生类有赋值重在函数,和上述情况相同(0,1)
class Person
{
private:
int idPerson;
public:
//Person():idPerson(1){} //没有给出
Person(int id) :idPerson(id) {} //带参构造函数
Person(const Person& per) :idPerson(per.idPerson)//拷贝构造
{
cout << "Copy Person" << endl;
}
Person& operator=(const Person& per)
{
if (this != &per)
{
idPerson = per.idPerson;
}
return *this;
}
void Dance()const
{
cout << "跳舞" << endl;
}
void PrintPerson()
{
cout << "身份证号" << idPerson << endl;
}
};
class Student :public Person
{
private:
int snum;
public:
//Student():Person(){} //error
Student() :Person(1), snum(0) {}
Student(int id, int s) :Person(id), snum(s) {}
Student(const Student& stud) :Person(stud), snum(stud.snum)//拷贝构造
{
cout << "Copy Student" << endl;
}
Student& operator=(const Student& stud)
{
if (this != &stud)
{
Person::operator=(stud);
((Person*)this)->operator=(stud); //强转为Person
}
return *this;
}
void Study()const
{
cout << "学习" << endl;
}
void PrintStudent()
{
PrintPerson();
cout << "学号" << snum << endl;
}
};
补充:切片现象,派生类对象赋值给基类对象时,会产生切片现象
四、继承面试题
设计一个类型,在外部环境中不能创建该类的对象
class Singleton
{
private://protected
Singleton(int x = 0) :value(x) {} //将构造函数设置为私有或者保护
int value;
Singleton(const Singleton&)=delete; //c11
Singleton& operator=(const Singleton&) = delete;
//~Singleton(){}
public:
~Singleton(){}
};
设计一个不能被继承的类
//将构造函数设计为私有的,但是不能为保护和公有
class non_herit
{
private:
non_herit(){}
public:
~non_herit(){}
};
class Base:public non_herit
{
public:
//Base():non_herit(){}
};
设计一个不能不继承的类,但是可以在外部环境创建该类的对象
方法一:单例模式
//单例模式
class Singleton
{
private://protected
Singleton(int x = 0) :value(x) {} //将构造函数设置为私有或者保护
int value;
Singleton(const Singleton&)=delete; //c11
Singleton& operator=(const Singleton&) = delete;
~Singleton(){}
public:
~Singleton(){}
static Singleton& getIntstance() //通过静态函数将对象创建出来
{
static Singleton s(10);
return s;
}
};
int main()
{
//Singleton s2 = Singleton::getIntstance();
Singleton &s2 = Singleton::getIntstance();
Singleton* sp = (Singleton*)malloc(sizeof(Singleton));
//*sp = s2; //不允许这样赋值,所以把赋值重载删掉了
}
方法二:使用final关键字 C11新标准
class non_herit final //不能派生出子类型,但是可以继承其他类
{
int value;
public:
non_herit(int x=0):value(x){}
non_herit(const non_herit&) = default;
non_herit& operator=(const non_herit&) = default;
~non_herit() = default;
};
设计一个能被继承的类,但是不能在外部环境创建该类的对象
class Object
{
protected:
Object(){}
Object(const Object &obj){}
Object& operator=(const Object& obj)
{
return *this;
}
};
class Base :public Object
{
public:
Base():Object(){}
};