C++构造函数 & 拷贝构造函数 & 派生类的构造函数 & 虚继承的构造函数
构造函数 ,是一种特殊的方法 。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。(摘自百度百科构造函数)。
一、最基本的构造函数
class Base
{
public:
Base(int var) : m_Var(var)
{
}
private:
int m_Var;
};
以上构造函数的执行过程:
1)传参 2)给类数据成员开辟空间 3)执行冒号语法给数据成员初始化 4)执行构造函数括号里面的内容
这里需要说明的是:冒号语法后面的内容相当于int a = 10;(初始化),而构造函数括号里面则是相当于是int a; a = 10;(赋初值)
二、拷贝构造函数
class Base
{
public:
Base(int var) : m_Var(var)
{
}
//拷贝构造函数
Base(Base &ref) : m_Var(ref.m_Var)
{
}
private:
int m_Var;
};
为什么拷贝构造函数的参数只能用引用呢?
这就要从拷贝构造函数式数码时候触发开始说起了,以下几种情况都会自动调用拷贝构造函数:
1)用一个已有的对象初始化一个新对象的时候
2)将一个对象以值传递的方式传给形参的时候
3)函数返回一个对象的时候
所以当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环直至栈溢出除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。(摘自百度百科拷贝构造函数)。
拷贝构造函数,一般不需要自己编写,系统默认的拷贝构造函数就能抗住了,但是有些情况需要在构造的时候开辟空间,这时候就需要拷贝构造函数了,如下代码是摘自林锐博士的高质量C++编程指南一文。
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String &other); // 拷贝构造函数
~ String(void); // 析构函数
private:
char *m_data; // 用于保存字符串
};
// String 的析构函数
String::~String(void)
{
delete [] m_data;
// 由于m_data 是内部数据类型,也可以写成 delete m_data;
} // String 的普通构造函数
String::String(const char *str)
{
if(str==NULL)
{
m_data = new char[]; // 若能加 NULL 判断则更好
*m_data = '\0';
}
else
{
int length = strlen(str);
m_data = new char[length+]; // 若能加 NULL 判断则更好
strcpy(m_data, str);
}
}
// 拷贝构造函数
String::String(const String &other)
{
int length = strlen(other.m_data);
m_data = new char[length+]; // 若能加 NULL 判断则更好
strcpy(m_data, other.m_data);
}
三、普通派生类构造函数的写法
定义派生类对象的时候,会按如下步骤执行构造操作:
1)传参 2)根据继承时的声明顺序构造基类 3)给类数据成员开辟空间 4)执行冒号语法后面的语句 5)执行构造函数函数体语句
class Base
{
public:
Base(int b) : m_b(b)
{
}
private:
int m_b;
}; class Derived : public Base
{
public:
//普通派生类构造函数的写法
Derived(int b, int d) : Base(b), m_d(d)
{
}
private:
int m_d;
};
再写一个多继承的示例:
class Base1
{
public:
Base1(int b1) : m_b1(b1)
{
}
private:
int m_b1;
}; class Base2
{
public:
Base2(int b2) : m_b2(b2)
{
}
private:
int m_b2;
}; class Derived : public Base1, public Base2
{
public:
Derived(int b1, int b2, int d) : Base1(b1), Base2(b2), m_d(d)
{ //注意冒号语法后面的顺序无所谓,创造基类是按照上面的继承声明顺序来进行的...
}
private:
int m_d;
};
四、含有虚继承的派生类构造函数的写法
为何要用到虚继承?
虚继承主要是针对多继承时,出现二义性问题而提出的。比如,如下代码就需要用到虚继承,否则的话Derived类继承时,Base类就会不明确。
虚继承构造函数的执行按照如下步骤:
1)传参 2)创建基类,注意这时候需要显示创建所有“有参构造函数”的基类,包括直接基类,间接基类。 3)给类数据成员开辟空间 4)执行冒号语法 5)执行构造函数函数体
注:你可能会疑惑,如下代码不是将Base间接基类创建了3次吗?其实不是这样的,编译器是这样处理的,当最远的派生类Derived创建了基类Base之后,其直接基类创建Base类的语句将会被忽略掉。
class Base
{
public:
Base(int b) : m_b(b)
{
}
private:
int m_b;
}; class Base1 : virtual public Base
{
public:
Base1(int b, int b1) : Base(b), m_b1(b1)
{
}
private:
int m_b1;
}; class Base2 : virtual public Base
{
public:
Base2(int b, int b2) : Base(b), m_b2(b2)
{
}
private:
int m_b2;
};
//虚继承,避免二义性
class Derived : public Base1, public Base2
{
public:
Derived(int b, int b1, int b2, int d) : Base(b), Base1(b, b1), Base2(b, b2), m_d(d)
{ //注意冒号语法后面的顺序无所谓,创造基类是按照上面的继承声明顺序来进行的...
}
private:
int m_d;
};
五、关于虚析构
虚析构一般伴随着多态而产生,多态主要方式就是用基类的指针或引用指向或引用派生类,而形成多态。
但是这样就会存在一个问题,当我们析构的时候,由于是基类的指针,就会调用的是基类的构造函数,从而造成派生内存溢出。为了解决这个问题,引入了虚析构的概念。将基类的构造函数声明为虚,从而使其在调用析构函数的时候能够准确的调用派生类的析构函数。
如下代码必须用到虚析构才能准确的析构派生类,并释放其占有内存。
class Base
{
public:
Base(int b) : m_b(b)
{
}
//虚析构,使基类指针能准确的释放所指向的派生类里面的内容
virtual ~Base()
{
}
private:
int m_b;
}; class Derived : public Base
{
public:
Derived(int b, char *pStr) : Base(b)
{
m_pStr = new char[strlen(pStr)+];
strcpy(m_pStr,pStr);
}
~Derived()
{
delete m_pStr;
m_pStr = NULL;
}
private:
char *m_pStr;
}; int main(void)
{
char *pStr = "abcdefg";
Base *b = new Derived(,pStr);
delete b; return ;
}
原文地址:http://www.cnblogs.com/nchar/p/3911427.html
C++构造函数 & 拷贝构造函数 & 派生类的构造函数 & 虚继承的构造函数的更多相关文章
- 多重继承,虚继承,MI继承中虚继承中构造函数的调用情况
先来测试一些普通的多重继承.其实这个是显而易见的. 测试代码: //测试多重继承中派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include < ...
- C++继承,多重继承,虚继承的构造函数以及析构函数的调用顺序问题
#include <iostream> using namespace std; class A{ int data_a; public: A(){ data_a = ; cout < ...
- C++进阶--派生类的析构(虚析构函数,shared_ptr)
//############################################################################ /* 在多态虚基类中声明一个虚析构函数 * ...
- 记录:C++类内存分布(虚继承与虚函数)
工具:VS2013 先说一下VS环境下查看类内存分布的方法: 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存 ...
- C++:派生类的构造函数和析构函数的调用顺序
一.派生类 在C++编程中,我们在编写一个基类的派生类时,大致可以分为四步: • 吸收基类的成员:不论是数据成员还是函数成员,派生类吸收除基类的构造函数和析构函数之外的全部成员. • 改造基类函数:在 ...
- C# 基类派生类构造函数执行顺序分析
using System; namespace ConsoleApp1 { class Program{ static void Main(string[] args){ B b = new B(); ...
- 【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符
学习资料 • 派生类的赋值运算符/赋值构造函数也必须处理它的基类成员的赋值 • C++ 基类构造函数带参数的继承方式及派生类的初始化 定义拷贝构造函数 [注意]对派生类进行拷贝构造时,如果想让基类的成 ...
- C++继承具体解释之二——派生类成员函数具体解释(函数隐藏、构造函数与兼容覆盖规则)
在这一篇文章開始之前.我先解决一个问题. 在上一篇C++继承详解之中的一个--初探继承中,我提到了在派生类中能够定义一个与基类成员函数同名的函数,这样派生类中的函数就会覆盖掉基类的成员函数. 在谭浩强 ...
- 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)
[源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...
随机推荐
- 一个ASPX页面的生命周期?
大家都知道客户端请求一个ASPX页面,通过iis中接收,会被的interinfo.exe进程截取,判断其扩展名,再把请求转交给ASPNET_ISAPI.DLL,通过isapi扩展进入相应的管道处理,转 ...
- J.Hilburn:高档男装市场颠覆者_网易财经
J.Hilburn:高档男装市场颠覆者_网易财经 J.Hilburn:高档男装市场颠覆者
- 用MFC完成一个简单的猜数字游戏: 输入的四位数中,位置和数字都正确为A,数字相同而位置不同的为B。
最近学习了MFC一些比较基础的知识,所以打算通过做一个简单的数字游戏来理解MFC的流程并进一步熟悉其操作. 在这里,我做了一个猜数字的小游戏.第一步当然是设计主界面,先给大家展示一下游戏界面: 主界面 ...
- POJ 3233 Matrix Power Series (矩阵+二分+二分)
题目地址:http://poj.org/problem?id=3233 题意:给你一个矩阵A,让你求A+A^2+……+A^k模p的矩阵值 题解:我们知道求A^n我们可以用二分-矩阵快速幂来求,而 当k ...
- JSP具体篇——out
out对象 out对象用于在web浏览器上输出信息,而且管理应用server上的输出缓冲区.在使用out对象输出数据时.能够对数据缓冲区进行操作.及时清除缓冲区中残留的数据.为其它输出让出缓冲空间. ...
- [Typescript] Introduction to Generics in Typescript
If Typescript is the first language in which you've encountered generics, the concept can be quite d ...
- 多表关联查询(ORACLE版)
前言:这几天学习oracle,把自己对于关联查询的理解,记录下.如有错误请指正! 交叉连接: 交欢连接又称为“笛卡儿积连接”,是两个或多个表之间的无条件连接.一个表中所有的记录与其它表的所有的记录进行 ...
- 【转】prufer编码
既然有人提到了,就顺便学习一下吧,来源:http://greatkongxin.blog.163.com/blog/static/170097125201172483025666/ 一个含有n个点的完 ...
- Android Studio错误
晚上一直在折腾android studio这个东西,弄的蛋疼.. 之前是有用的,然后今天闲的没事干,更新了下,反正弄出了一大堆的错误.. 错误:failed to find Build Tools r ...
- Java字符串的10大热点问题,你都懂吗?
转自 威哥干JAVA http://www.codingke.com 下面我为大家总结了10条Java开发者经常会提的关于Java字符串的问题,如果你也是Java初学者,仔细看看吧: 1.如何比较字符 ...