博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c++学习笔记:类的若干基础问题
阅读量:4685 次
发布时间:2019-06-09

本文共 3517 字,大约阅读时间需要 11 分钟。

1. 为什么需要在类定义后面’}'后面加分号

c++的class定义后面可以接一个对象定义列表,当然这并不是一个很好的编程习惯,但c++是支持的.

001
002
003
class
B{
    
//成员变量和函数
}b1,b2;

这个定义了类B,以及B的两个对象b1和b2.

2. 对象的初始化

如果没有给类定义构造函数,c++编译器会自动生成一个构造函数去初始化这些值,比如string成员会初始化为空字符串.

构造函数中的初始化列表是初始化阶段运行,而构造函数中的语句,则属于运算阶段,在这些语句运行前,实际上类的成员变量们就已经完成了初始化过程,构造函数内部对成员变量的改编只是一种赋值和运算行为.

比如:

001
002
003
004
005
006
007
class
A{
public
:
    
A(
int
val):data(val){ cout<<data<<endl; }
    
void
print(){cout<<data<<endl;}
private
:
    
const
int
data;
};

我们知道const类型只能在初始化时给定值,而不能之后赋值,所以,必须在初始化列表中给data初始化,而不能在函数体中去赋值.其他非const的成员即使初始化列表没有指定,进入函数体时,也已经有了相应的初始化值,int型可能是某个随机值.

成员初始化的顺序与类的声明顺序一致.

二. 构造函数

关于构造函数还有更多复杂的专题,将另外重新写博客阐述.

构造函数是可以重载的,编译器通过实参决定到底调用哪个构造函数

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
#include <iostream>
#include <string>
using
namespace
std;
class
A{
public
:
    
A(
int
n,
int
m):data(10){ cout<<data<<endl; }
    
A(
float
n,
float
m):data(12){ cout<<data<<endl; }
private
:
    
int
data;
};
 
int
main()
{
    
A obj1(1,2.0);
//10
    
A obj2(1,2);
//10
    
A obj3(1.0f,2.0f);
//12
    
A obj4(1.0,2.0);
//Error,不明确
    
return
0;
}

另外隐式的类类型转换通常也是通过构造函数完成的。

看如下的代码:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
#include <iostream>
#include <string>
using
namespace
std;
 
class
A{
public
:
    
A(
int
n):data(n,
'a'
){ cout<<data<<endl; }
    
A(string str):data(str){ cout<<data<<endl; }
private
:
    
string data;
};
 
//函数形参为A类型
//空函数
void
f(A obj)
{
}
 
int
main()
{
    
//调用对应构造函数生成临时对象
    
f(5);
    
string myString(
"hello,world!"
);
    
//调用对应的构造函数
    
f(myString);
    
return
0;
}

函数f的形参应该为A类型,但如果我们传入int或者string类型,编译器会调用相应的构造函数进行隐式的类型转换,生成一个临时的A的对象.

如果要禁止这种隐式转换,可以使用关键字explicit(这个关键字只能用于类的内部构造函数声明,外部定义或者其他非构造函数不能使用).

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
#include <iostream>
#include <string>
using
namespace
std;
 
class
A{
public
:
    
explicit
A(
int
n):data(n,
'a'
){ cout<<data<<endl; }
    
explicit
A(string str):data(str){ cout<<data<<endl; }
private
:
    
string data;
};
 
//函数形参为A类型
//空函数
void
f(A obj)
{
}
 
int
main()
{
    
//不能再使用直接传入5
    
// error C2664: “f”: 不能将参数 1 从“int”转换为“A”
    
//f(5);
    
f(A(5));
    
string myString(
"hello,world!"
);
    
// error C2664: “f”: 不能将参数 1 从“std::string”转换为“A”
    
//f(myString);
    
f(A(myString));
    
return
0;
}

三. this指针

MSDN中关于this指针的描述是:

The this pointer is a pointer accessible only within the nonstatic member functions of a class, struct, or union type. It points to the object for which the member function is called. Static member functions do not have a this pointer.

static的成员变量或者函数是没有this指针的,(实际上static成员是属于类的,而不是属于对象,是同一类的对象间共享的,根本不可能有this指针).另外this指针实际上并不是对象本身的一部分,sizeof一个对象的计算值也并没有把它计算在内.

下面的代码:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
#include<iostream>
using
namespace
std;
 
class
Simple
{
private
:
    
int
m_nID;
public
:
    
Simple(
int
nID)
    
{
        
SetID(nID);
    
}
    
void
SetID(
int
nID) { m_nID = nID; }
    
int 
GetID() {
return
m_nID; }
};
 
int
main()
{
    
Simple myob(5);
    
myob.SetID(3);
    
cout<<myob.GetID()<<endl;
    
return
0;
}

其中myob.SetID(3)实际上被编译器解释为SetID(&myob,3),把对象的地址作为隐含的参数传给函数。

另外this指针也可以用于防止自我调用.

四. const关键字有关

001
double
avg_price()
const
;
将关键字const加入形参表之后,表示这个成员函数不能改变所操作的对象的数据成员,const必须同时出现在声明和定义中。
关于为什么,更进一步的讨论如下:
(1).在普通的非const成员函数中,this的类型是一个指向类类型的const指针,可以改变this所指向的值,但是不能改变this所保存的地址.
(2).而在const成员函数中,this的类型是一个指向const对象的const指针,指向的值和保存的地址都不能改变.
所以如果试图在const成员函数中返回this指针,必须说明返回的类型为
const myClass&
声明为mutable的成员是可变成员,即使在const对象或者const成员函数中也可以改变它的值.

转载于:https://www.cnblogs.com/shihao/archive/2012/01/18/2325560.html

你可能感兴趣的文章
[LeetCode] Perfect Squares
查看>>
深入理解springAOP
查看>>
Log4j 2环境配置和适配组件配置(maven/ivy/gradle)
查看>>
实验二
查看>>
转载 8天掌握EF的Code First开发之Entity Framework介绍
查看>>
单元测试NUnit 的文章
查看>>
poj 1787
查看>>
windows cmd
查看>>
一段js代码的分析
查看>>
免费邮件服务器:MailEnable
查看>>
v-if与v-show区别
查看>>
M25-2
查看>>
字符串反转-vue
查看>>
理解inode(转)
查看>>
改变linux默认配色方案(dircolors和dircolors-solarized使用)
查看>>
不知还有人遇到这个问题没有:数据库 'xxx' 的版本为 706,无法打开。此服务器支持 661 版及更低版本。不支持降级路径。...
查看>>
[转载]CAsyncSocket及CSocket注解
查看>>
phpcms自定义表单添加验证码验证功能
查看>>
P2896 [USACO08FEB]一起吃饭Eating Together
查看>>
翻译链接
查看>>