C++c 面试常见问题 类

C++之类的内存分配问题
一个类,有成员变量:静态与非静态之分;而成员函数有三种:静态的、非静态的、虚的。
那么这些个东西在内存中到底是如何分配的呢?
以一个例子来说明:
#include"iostream.h"
class&CObject
&static&int&a;
& &CObject();
&~CObject();
&void&Fun();
private:& &int&m_& &int&m_
};void&CObject::Fun()
& &cout&&"Fun\n"&&
CObject::CObject()
& &cout&&"Construct!\n";
CObject::~CObject()
& &cout&&"Destruct!\n";
}int&CObject::a=1;void&main()
cout&&"Sizeof(CObject):"&&sizeof(CObject)&&&cout&&"CObject::a="&&CObject::a&&
CObject myO
cout&&"sizeof(myObject):"&&sizeof(myObject)&&
cout&&"sizeof(int)"&&sizeof(int)&&
这是我的一段测试代码,&
运行结果是:&
Sizeof(CObject):8&
CObject::a=1&
Construct!&
sizeof(myObject):8&
sizeof(int)4&
Destruct!&
我有疑问如下:&
(1)C++中,应该是对象才会被分配内存空间吧??为什么CObject内存大小是8,刚好和两个成员变量的大小之和一致!难道还没实例化的时候,类就已经有了内存空间了?&
(2)当对象生成了之后,算出的内存大小怎么还是8,函数难道不占用内存空间吗?至少应该放个函数指针在里面的吧?内存是怎样布局的?
(3)静态成员应该是属于类的,怎么类的大小中没有包含静态成员的大小?
下面分别解答如下:
1)Sizeof(CObject)是在编译时就计算了的,一个类定义了,它所占的内存编译器就已经知道了,这时只是得到它占用的大小,并没有分配内存操作
。也可以这样想:编译器肯定知道大小了,这与分配内存空间无关,知道大小了,以后实例化了才能知道要分配多大。
2)类的普通成员、静态成员函数是不占类内存的,至于你说的函数指针在你的类中有虚函数的时候存在一个虚函数表指针,也就是说如果你的类里有虚函数则sizeof(CObject)的值会增加4个字节。
其实类的成员函数实际上与普通的全局函数一样。&
只不过编译器在编译的时候,会在成员函数上加一个参数,传入这个对象的指针。
成员函数地址是全局已知的,对象的内存空间里根本无须保存成员函数地址。&
对成员函数(非虚函数)的调用在编译时就确定了。&
像 myObject.Fun() 这样的调用会被编译成形如 _CObject_Fun(
&myObject ) 的样子。
函数是不算到sizeof中的,因为函数是代码,被各个对象共用,跟数据处理方式不同。对象中不必有函数指针,因为对象没必要知道它的各个函数的地址(调用函数的是其他代码而不是该对象)。&
类的属性是指类的数据成员,他们是实例化一个对象时就为数据成员分配内存了,而且每个对象的数据成员是对立的,而成员函数是共有的~&
静态成员函数与一般成员函数的唯一区别就是没有this指针,因此不能访问非静态数据成员。总之,程序中的所有函数都是位于代码区的。
3)静态成员并不属于某个对象,sizeof取的是对象大小。
知道了上面的时候,就可以改一下来看看:
我也补充一些:&
CObject();&
~CObject();&
//这里改成了double&
这个类用sizeof()测出来的大小是
2*sizeof(double)=16&
CObject();&
~CObject();&
//这里改成了char&
大小是2*sizeof(int)=8&
CObject();&
~CObject();&
//这里改成了double&
sizeof(char)+sizeof(int)
&sizeof(double)
所以大小是2*sizeof(double)&
其实这里还有一个是内存对齐的问题。
空类大小是1。&
另外要注意的一些问题:
先看一个空的类占多少空间?
class&Base&&
&&&&Base();&&
&&&&~Base();&&
Base { public: Base(); ~Base(); };
注意到我这里显示声明了构造跟析构,但是sizeof(Base)的结果是1.
因为一个空类也要实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含
的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。
而析构函数,跟构造函数这些成员函数,是跟sizeof无关的,也不难理解因为我们的sizeof是针对实例,而普通成员函数,是针对类体的,一个类的成
员函数,多个实例也共用相同的函数指针,所以自然不能归为实例的大小,这在我的另一篇博文有提到。
接着看下面一段代码
class&Base&&
&&&&Base();&&&&&&&&&&&&&&&&&&
&&&&virtual&~Base();&&&&&&&&&//每个实例都有虚函数表&&
&&&&void&set_num(int&num)&&&&//
普通成员函数,为各实例公有,不归入sizeof统计&&
&&&&&&&&a=&&
private:&&
&&&&int&&a;&&&&&&&&&&&&&&&&&&//占4字节&&
&&&&char&*p;&&&&&&&&&&&&&&&&&//4字节指针&&
class&Derive:public&Base&&
&&&&Derive():Base(){};&&&&&&&
&&&&~Derive(){};&&
private:&&
&&&&static&int&&&&&&&&&&//非实例独占&&
&&&&int&&d;&&&&&&&&&&&&&&&&&&&&&//占4字节&&
&&&&char&*p;&&&&&&&&&&&&&&&&&&&&//4字节指针&&
int&main()&&&
&&&&cout&&sizeof(Base)&&&&
&&&&cout&&sizeof(Derive)&&&&
&&&&return&0;&&
Base { public: Base(); virtual ~Base(); //每个实例都有虚函数表 void
set_num(int num) //普通成员函数,为各实例公有,不归入sizeof统计 { a= } private:
//占4字节 char *p; //4字节指针 }; class Derive:public Base {
public: Derive():Base(){}; ~Derive(){}; private:
//非实例独占 //占4字节 char *p; //4字节指针 }; int main() {
cout&&sizeof(Base)&&
cout&&sizeof(Derive)&&
return 0; }
结果自然是
Base类里的int&char
*p;占8个字节。
而虚析构函数virtual ~Base();的指针占4子字节。
其他成员函数不归入sizeof统计。
Derive类首先要具有Base类的部分,也就是占12字节。
*p;占8字节
不归入sizeof统计
所以一共是20字节。
在考虑在Derive里加一个成员
class&Derive:public&Base&&
&&&&Derive():Base(){};&&
&&&&~Derive(){};&&
private:&&
&&&&static&int&&&
&&&&int&&d;&&
&&&&char&*p;&&
&&&&char&c;&&
Derive:public Base { public: Derive():Base(){}; ~Derive(){};
private: char *p; };
这个时候,结果就变成了
c;增加了4字节,说明类的大小也遵守类似class字节对齐,补齐规则。
具体的可以看网上那篇《5分钟搞定字节对齐》
至此,我们可以归纳以下几个原则:
1.类的大小为类的非静态成员数据的类型大小之和,也就是说静态成员数据不作考虑。
2.普通成员函数与sizeof无关。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。C++11标准下有关静态成员的类内初始化问题?
C++ primer上这样描述:&br&Ordinarily, class static members may not be initialized in the class body. However,&br&we can provide in-class initializers for static members that have const integral&br&type and&b& must do so for static members that are constexprs of literal type.The initializers must be constant expressions.&/b&&br&黑色字体我翻译成:用常量表达式初始化的字面值类型的constexpr静态成员也可以为其提供类内初始值。&br&这里的literal type,指在编译时就能计算得到的,一般,算数类型、引用和指针都属于字面值类型。&br&请看以下代码:&br&&div class=&highlight&&&pre&&code class=&language-cpp&&&span class=&kt&&int&/span& &span class=&n&&ival&/span& &span class=&o&&=&/span& &span class=&mi&&10&/span&&span class=&p&&;&/span&
&span class=&k&&class&/span& &span class=&nc&&Test&/span&
&span class=&p&&{&/span&
&span class=&k&&static&/span& &span class=&k&&constexpr&/span& &span class=&kt&&int&/span& &span class=&o&&&&/span&&span class=&n&&_ival&/span& &span class=&o&&=&/span& &span class=&n&&ival&/span&&span class=&p&&;&/span&
&span class=&p&&};&/span&
&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&()&/span&
&span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&以上代码可以顺利编译通过。&br&但是以下代码却不能:&br&&div class=&highlight&&&pre&&code class=&language-cpp&&&span class=&k&&const&/span& &span class=&kt&&int&/span& &span class=&n&&ival&/span& &span class=&o&&=&/span& &span class=&mi&&10&/span&&span class=&p&&;&/span&
&span class=&k&&class&/span& &span class=&nc&&Test&/span&
&span class=&p&&{&/span&
&span class=&k&&static&/span& &span class=&k&&constexpr&/span& &span class=&k&&const&/span& &span class=&kt&&int&/span& &span class=&o&&&&/span&&span class=&n&&_ival&/span& &span class=&o&&=&/span& &span class=&n&&ival&/span&&span class=&p&&;&/span&
&span class=&p&&};&/span&
&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&()&/span&
&span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&gcc报错为:&br& error: non-constant in-class initialization invalid for static member ‘test::_ival’&br& error: (an out of class initialization is required)&br& error: ‘test::_ival’ cannot be initialized by a non-constant expression when being
declared&br&可是&b& ival&/b& 明明是常量表达式啊,为什么会出错?
C++ primer上这样描述:Ordinarily, class static members may not be initialized in the class body. However,we can provide in-class initializers for static members that have const integraltype and must do so for static members that are constexprs of literal type.The initializers must be constant expressions.黑色字体我翻译成:用常量表达式初始化的字面值类型的constexpr静态成员也可以为其提供类内初始值。这里的literal type,指在编译时就能计算得到的,一般,算数类型、引用和指针都属于字面值类型。请看以下代码:int ival = 10;
class Test
static constexpr int &_ival = ival;
int main()
以上代码可以顺利编译通过。但是以下代码却不能:…
按投票排序
谢邀,我在mingw的环境下试了一下问题中的代码,确实产生了同样的问题。于是去查了一下c++11的标准,发现和Primer给出的描述应该是一致的,所以做了一些探索。总结了一下探索的内容:int ival = 10;
const int const_ival = 10;
constexpr int const
& cival_g = ival;
constexpr int const
& cival_g_c = const_ival;
class Test
static constexpr
int const & _ival = ival;
// static constexpr
int const & _ival_c = const_
int main() {
除了其中注释掉的一行以外,其余内容均编译通过。用错误信息改善后的gcc 4.8跑的结果是:test.cpp:12:43: error: non-constant in-class initialization invalid for static m
ember 'Test::_ival_c'
static constexpr
int const & _ival_c = const_
test.cpp:12:43: error: (an out of class initialization is required)
test.cpp:12:43: error: 'Test::_ival_c' cannot be initialized by a non-constant e
xpression when being declared
可以看到gcc认为const_ival不是一个constant expression,但是在类外定义的时候又毫无疑问的没有问题.... 不由让人觉得这可能是gcc的一个bug,建议到gcc邮件组里面去问一下。顺便使用指针是没有问题的:static constexpr
int const * _ival_c = &const_ 补充在网上找了几个online的compiler测试,发现vs2013和clang3.2 clang3.3都是可以编译的,因此这很大可能是gcc的bug
使用Clang++编译楼主的那段GCC出错的程序,完全没有错误啊,即使开了-Wall也没有任何信息$ clang++ --version
Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix
我在中间加了些东西让防止编译器忽略掉没有调用过的class Test,也没有任何Errors或Warnings
第二段代码中,constexpr const &int应该能绑定到const int上,目测应该是gcc的bug,因为这个错误信息:“‘test::_ival’ cannot be initialized by a non-constant expression”显然是瞎扯。顺便说一句,clang 3.2~3.4均顺利编译无碍。
我又仔细翻了下primer,并粗粗翻了下c++11标准,primer上这样写:Under the new standard, we can ask the compiler to verify that a variable is aconstant expression by declaring the variable in a constexpr declaration. Variablesdeclared as constexpr are implicitly const and must be initialized by constantexpressions.因此被声明为constexpr的对象是一个隐式的const,而constexpr最大的作用是去验证所声明的变量是不是一个常量表达式。Although we can define both pointers and reference as constexprs, the objects weuse to initialize them are strictly limited. We can initialize a constexpr pointer fromthe nullptr literal or the literal (i.e., constant expression) 0. We can also point to(or bind to) an object that remains at a fixed address.For reasons we’ll cover in § 6.1.1 (p. 204), variables defined inside a functionordinarily are not stored at a fixed address. Hence, we cannot use a constexprpointer to point to such variables. On the other hand, the address of an object definedoutside of any function is a constant expression, and so may be used to initialize aconstexpr pointer. We’ll see in § 6.1.1 (p. 205), that functions may define variablesthat exist across calls to that function. Like an object defined outside any function,these special local objects also have fixed addresses. Therefore, a constexprreference may be bound to, and a constexpr pointer may address, such variables.也就是说,我们可以用全局性的对象的地址来初始化constexpr对象,也可用全局性的对象来绑定constexpr引用。It is important to understand that when we define a pointer in a constexprdeclaration, the constexpr specifier applies to the pointer, not the type to which thepointer points.这表明了constexpr仅仅对指针有效(也就是将指针隐式定义为const),而对指针所指的对象无关。primer中对constexpr引用没有特别的说明。但是我个人觉得是这样的:由于引用本身并非对象,我们不可能用constexpr将引用本身隐式定义为const,所以constexpr在此处的作用只不过是验证:是否是 存放在固定地址的对象来绑定constexpr所声明的引用的。与指针类似,此处constexpr仅仅对引用本身有效,而对所引用的对象无关。我做了以下尝试来验证:const int ival = 10;
int main()
constexpr int &_ival = ival;
cout && _ival && endl;
gcc报错为:error: invalid initialization of reference of type ‘int&’ from expression of type ‘const int’而以下代码顺利通过:const int ival = 10;
int main()
constexpr const int &_ival =
cout && _ival &&
这样结果就很显然啦!
因此轮子哥
我还是觉得constexpr const int &_ival =
_ival是个常量引用 城哥
,我感觉以下代码constexpr int const
& cival_g =
constexpr int const
& cival_g_c = const_
static constexpr
int const & _ival =
写成下面的样子会更好constexpr const int & cival_g =
constexpr const int & cival_g_c = const_
static constexpr const int & _ival =
因为引用本身不是对象,它只可能是底层const,而constexpr才会作用在引用cival_g上。而我原先的第二段代码,我也觉得编译不过,是gcc的bug。。
已有帐号?
无法登录?
社交帐号登录C++类对象指针作为函数参数应用的问题
[问题点数:20分,结帖人jierandefeng]
C++类对象指针作为函数参数应用的问题
[问题点数:20分,结帖人jierandefeng]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。学习c++的类中遇到的一个问题
class Position {public:};class Robot {public: Robot();
/* default constructor, initialize at (0,0) */ Robot(Position pos);
/* initialize at pos */ void Move(char Dir);
/* Dir could be 'N', 'E', 'S', 'W', for other characters, the robot don’t move */ Position GetPosition();
/* return current position */private: Position currentP};Robot::Robot(Position pos);
/* initialize at pos */这个一直报错请问是什么问题
写下你的评论...
Copyright (C)
All Rights Reserved | 京ICP备 号-2}

我要回帖

更多关于 小米4c刷机出现问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信