C++类的构造、拷贝构造、析构函数等
1:
一个空的class在C++编译器处理过后就不再为空,编译器会自动地为我们声明一些member function,如果你写
class A{};
编译器处理后,就相当于:
class A
{
public:
A(); //默认构造函数
A(const A&); //拷贝构造函数
~A(); //析构函数
A& operator=(const A& rhs);
A* operator&(); //取地址运算符
const A* operator&() const;
};
基本上符合我上文的回答,只是多了取地址运算符的两个函数。
这种回答对否?
其实对于这样的一个空类来说,是完全没有必要的,而编译器也不是这样做的。编译器的做法是:
只有你需要用到这些函数并且你又没有显示的声明这些函数的时候,编译器才会贴心的自动声明相应的函数。
比如
A a;
编译器就会根据上面的实例,给类A生成构造函数和析构函数。
当使用
A b(b);
编译器就会生成类A的拷贝构造函数。
A c;
c = a;
编译器生成赋值运算符函数
A &d = a;
编译器生成取地址运算符函数。
经过我们的分析可以这样理解:对于一个没有实例化的空类,编译器是不会给它生成任何函数的,当实例化一个空类后,编译器会根据需要生成相应的函数。这条理论同样适合非空类(只声明变量,而不声明函数)。
2
类的const成员变量、static const、static成员变量的初始化
结论:
- 静态常量数据成员可以在类内初始化(即类内声明的同时初始化),也可以在类外,即类的实现文件中初始化,不能在构造函数中初始化,也不能在构造函数的初始化列表中初始化;
- 静态非常量数据成员只能在类外,即类的实现文件中初始化,也不能在构造函数中初始化,不能在构造函数的初始化列表中初始化;
- 非静态的常量数据成员不能在类内初始化,也不能在构造函数中初始化,而只能且必须在构造函数的初始化列表中初始化;
- 非静态的非常量数据成员不能在类内初始化,可以在构造函数中初始化,也可以在构造函数的初始化列表中初始化;
总结如下表:
类型 初始化方式 |
类内(声明) |
类外(类实现文件) |
构造函数中 |
构造函数的初始化列表 |
非静态非常量数据成员 |
N |
N |
Y |
Y |
非静态常量数据成员 |
N |
N |
N |
Y (must) |
静态非常量数据成员 |
N |
Y (must) |
N |
N |
静态常量数据成员 |
Y |
Y |
N |
N |
/**
* <Effective C++>, page 14
* const data of class
* platform: visual studio 2005, win32
* filename: item2.1.cpp
*/
#include <iostream>
using namespace std;
class MyTest
{
//(1) error C2864: 'MyTest::MaxNumber1' : only static const integral data members can be initialized within a class
//int MaxNumber1 = 5;
//(2) error C2864: 'MyTest::MaxNumber2' : only static const integral data members can be initialized within a class
//const int MaxNumber2 = 5;
//(3) error C2864: 'MyTest::MaxNumber3' : only static const integral data members can be initialized within a class
//static int MaxNumber3 = 5;
//(4) ok
static const int MaxNumber4 = ;
static const char cconst4 = 'B';
//(5) error C2864: 'MyTest::dconst4' : only static const integral data members can be initialized within a class
//static const double dconst4 = 200.00;
public:
//(6) error C2758: 'MyTest::MaxNumber2' : must be initialized in constructor base/member initializer list
MyTest()
{
cout<<"MyTest constructor! "<<endl;
cout<<"MaxNumber4 = "<<MaxNumber4<<endl;
cout<<"cconst4 = "<<cconst4<<endl;
}
};
int main()
{
MyTest obj; return ;
}
代码注释中的(1),(2),(3)表示step编号。
从(1),(2),(3)中,我们可以看出,只有static const integral data member(静态整型常量数据成员)才能在类内初始化。从(4),(5)中也可以得到证明。其中,char型相当于整型。
运行结果如下。
MyTest constructor!
MaxNumber = 5
cconst1 = A
cconst2 = B
dconst1 = 100
/**
* <Effective C++>, page 14
* const data of class
* platform: visual studio 2005, win32
* filename: item2.2.cpp
*/
#include <iostream>
using namespace std;
class MyTest
{
int MaxNumber1;
const int MaxNumber2;
static int MaxNumber3;
static const int MaxNumber4 = ;
static const char cconst4 = 'B';
static const int MaxNumber5;
public:
//(1) error C2758: 'MyTest::MaxNumber2' : must be initialized in constructor base/member initializer list
//(4) error C2438: 'MaxNumber3' : cannot initialize static class data via constructor
//(7) error C2438: 'MaxNumber5' : cannot initialize static class data via constructor
MyTest():MaxNumber1(), MaxNumber2()//, MaxNumber5(5)//, MaxNumber3(5)
{
//(2) error C2166: l-value specifies const object
//MaxNumber2 = 5;
//(3) error LNK2001: unresolved external symbol "private: static int MyTest::MaxNumber3" (?MaxNumber3@MyTest@@0HA)
//MaxNumber3 = 5;
//(6) error C3892: 'MaxNumber5' : you cannot assign to a variable that is const
//MaxNumber5 = 5;
cout<<"MyTest constructor! "<<endl;
cout<<"MaxNumber1 = "<<MaxNumber1<<endl;
cout<<"MaxNumber2 = "<<MaxNumber2<<endl;
cout<<"MaxNumber3 = "<<MaxNumber3<<endl;
cout<<"MaxNumber4 = "<<MaxNumber4<<endl;
cout<<"MaxNumber5 = "<<MaxNumber5<<endl;
cout<<"cconst4 = "<<cconst4<<endl;
}
};
//(5) ok
int MyTest::MaxNumber3 = ;
//(8) ok
const int MyTest::MaxNumber5 = ;
//(9) error C2761: 'int MyTest::MaxNumber1' : member function redeclaration not allowed
//int MyTest::MaxNumber1 = 5;
int main()
{
MyTest obj;
return ;
}
运行结果如下。
MyTest constructor!
MaxNumber1 = 5
MaxNumber2 = 5
MaxNumber3 = 5
MaxNumber4 = 5
MaxNumber5 = 5
cconst4 = B
代码注释中的(1),(2),(3)表示step编号。
从(1),(2)可以看出,非静态的常量数据成员必须在构造函数的初始化列表中初始化;如果在构造函数中初始化,会出现error c2166的错误,即常量对象是只读(read only)的,不能对其赋值。
从(3),(4),(5)可知,静态非常量数据成员只能在类外(类的实现文件)初始化。
从(6),(7),(8)可知,静态常量数据成员也可以在类外(类的实现文件)初始化。
3 初始化顺序
c++ 中类变量的初始化顺序,大体如下:
- 基类的静态成员初始化;
- 派生类的静态成员初始化;
- 基类的对象成员初始化;
- 基类的构造函数;
- 派生类的对象成员初始化;
- 派生类的构造函数;
#include <iostream>
using namespace std; class Inner{
public:
Inner(int i=): in(i) { cout << "Inner.constructor. " << in<<"\n";}
Inner(Inner& inner): in(inner.in) { cout << "Inner.copy consturctor" << "\n";};
int getValue(){ return in; } private:
int in;
}; class Inner2{
public:
Inner2(double i=0.0): in2(i) { cout << "Inner2.constructor. " << in2<<"\n";}
Inner2(Inner2& inner2): in2(inner2.in2) { cout << "Inner2.copy consturctor" << "\n";};
int getValue(){ return in2; }
private:
double in2;
}; class Base{
public:
Base(int v=): value(v){ value = ; cout << "Base.constructor. " << value<<"\n";}
Base(Base& b): value(b.value) { cout << "Base.copy consturctor" << "\n";}
int getValue(){ return value; }
protected:
int value;
Inner2 inner2;
static Inner inner;
static int baseInt;
}; Inner Base::inner();
int Base::baseInt = ; class Derive: public Base{
public:
Derive(string s = "hello", int base=, int i=, double i2=): derive(s), in2(i2), in(i) { cout << "derive.derive == " << derive << ", Derive.consturctor" << "\n";};
//Derive(string s = "hello", int base=0, int i=0, double i2=0){ cout << "Derive.consturctor" << "\n";};
Derive(Derive& d): derive(d.derive) { cout << "Derive.copy consturctor" << "\n";}
void printValue(){
cout << "derive.base.value == " << value << ", derive.derive == " << derive <<
", derive.in == " << in.getValue() << ", derive.in2 == " << in2.getValue()
<<"base int: "<<baseInt<< "\n"; } private:
string derive;
Inner in;
Inner2 in2;
static Inner inner;
//static int baseInt;
}; Inner Derive::inner();
int main()
{
Derive d("world", , , 30.0);
d.printValue();
// Derive d2 = d;
cout << endl;
}Inner.constructor. 1000
Inner.constructor. 100
Inner2.constructor. 0
Base.constructor. 1
Inner.constructor. 20
Inner2.constructor. 30
derive.derive == world, Derive.consturctor
derive.base.value == 1, derive.derive == world, derive.in == 20, derive.in2 == 30base int: 100
C++类的构造、拷贝构造、析构函数等的更多相关文章
- C++ //构造函数的分类及调用 //分类 // 按照参数分类 无参构造函数(默认构造) 有参构造函数 //按照类型分类 普通构造 拷贝构造
1 //构造函数的分类及调用 2 //分类 3 // 按照参数分类 无参构造函数(默认构造) 有参构造函数 4 //按照类型分类 普通构造 拷贝构造 5 6 #include <iostream ...
- C++派生类的拷贝构造
一. 概述 通过几个简单的实验,回顾下派生类中拷贝构造的相关知识. 环境:Centos7 64位, g++ 4.8.5 在继承中,构造器与析构器均没有被继承下来.拷贝构造,也是一种构造,也没有被继承下 ...
- C++ 构造函数、析构函数、拷贝构造、赋值运算符
之所以要把它们放在一起,是因为在使用C/C++类语言的时候,很容易混淆这几个概念(对Java来说完全没有这样的问题,表示Javaor完全没有压力). 先建立一个测试类(包含.h和.cpp) //~ P ...
- 10.C++-构造函数初始化列表、类const成员、对象构造顺序、析构函数
首先回忆下,以前学的const 单独使用const修饰变量时,是定义的常量,比如:const int i=1; 使用volatile const修饰变量时,定义的是只读变量 使用const & ...
- 构造函数和初始化表、this指针与常函数、析构函数、拷贝构造与拷贝赋值(day05)
十四 构造函数和初始化表 ... 初始化表 )语法形式 class 类名{ 类名(形参表):成员变量1(初值),...{} }; )必须要使用初始化表的场景 -->如果有类 类型的成员变量,而该 ...
- C++ Primer笔记9_构造函数_拷贝构造(深拷贝与浅拷贝)
1.构造函数: >构造函数是一个特殊的.与类同名的成员函数,用于给每一个成员设置适当的初始值. >构造函数不能有返回值,函数名与类名同样. >缺省构造函数时,系统将自己主动调用该缺省 ...
- C++拷贝构造&操作符重载
头文件 DString.h如下 #ifndef __DSTRING_H #define __DSTRING_H #endif #include <stddef.h> class DStri ...
- c++ 拷贝构造练习
#include<iostream> using namespace std; class Vector { private: int *dwp; int size; void clone ...
- C++对象的构造、析构与拷贝构造
今天下午在研究虚函数的时候遇到了一个问题,觉得很有意思,记录一下. 先看代码: class Base { public: Base(int value) { m_nValue = value; cou ...
随机推荐
- 【BZOJ】【2440】【中山市选2011】完全平方数
莫比乌斯函数/容斥原理 PoPoQQQ讲义引入例题= = 比较水……就是莫比乌斯函数的简单应用,也可理解为乱容斥一下…… 二分答案——>求1~x有多少个无平方因子的数Q(x). 引用一下PoPo ...
- Matlab中find函数的使用
一.问题来源 看到了 min_score_pos = find(A0_scores==min(A0_scores), 1); [r,c] = find(X,k),返回X中第k个非零元素的行列位置. 二 ...
- [CFgym]2015-2016 ACM-ICPC Pacific Northwest Regional Contest小结
*感谢两位浙江大佬带我飞 贴下成绩 div2 div1 *div2不是我打的上个厕所就5/11了 比赛小结 A [题目大意] 有n(n<=500)个机场,两两之间距离是g[i][j],每经停一个 ...
- 使用了非标准扩展:“xxx”使用 SEH,并且“xxx”有析构函数
如果一个函数内使用了异常处理机制, VC 编译器在编译该函数时,它会给此函数插入一些“代码和信息”(代码指的是当该函数中出现异常时的回调函数,而信息主要是指与异常出现相关的一些必要的链表),因此每份函 ...
- Ubuntu下非常给力的下载工具--uget+aria2
转自Ubuntu下非常给力的下载工具--uget+aria2 Windows下的下载工具--迅雷,之所以下载速度快,乃是它能搜索资源.为己所用,而不是仅仅从原始地址这单一资源处下载. Ubuntu下也 ...
- [转载]Spring Bean Configuration Inheritance
转自: http://www.mkyong.com/spring/spring-bean-configuration-inheritance/ In Spring, the inheritance i ...
- PHP图标类库 - JpGraph使用详解
http://w3note.com/web/181.html 微信平台开发的推广支持应用里,为了满足用户渠道推广分析的需要,公众平台提供了生成带参数二维码的接口.使用该接口可以获得多个带不同场景值的二 ...
- hdu 4111 Alice and Bob 博弈论
这里有2种方法: 方法一:求SG函数 sg[i][j]:i表示1的个数,j表示合并操作的步数. 这共有4种操作: 1.消除一个1: 2.减掉一个1: 3.合并2个1: 4.把1合并到另外不是1中. 代 ...
- String类的使用 Part2
StringBuilder 类的使用 属性: namespace StringBuilderTest { class Program { static void Main(string[] args) ...
- FFMpeg那些事——独立运行的二进制文件ffmpeg编译
想编译一个Android可用的二进制文件(要求:支持libx264/liblamemp3) github资源: 1.首先编译一个带lame库的ffmpeg https://github.com/aks ...