c++ 15个语言特性,C++语言的15个晦涩特性(3)

本文详细介绍了C++中指针到成员操作符的使用,包括*和->的区别,并讨论了成员函数指针与普通函数指针的不同,以及在库如Boost::Python中的应用。此外,文章还涉及自定义操作符重载,特别是处理++和--操作符的技巧。
摘要由CSDN通过智能技术生成

指向成员的指针操作符

指向成员的指针操作符可以让你在一个类的任何实例上描述指向某个成员的指针。有两种pointer-to-member操作符,取值操作符*和指针操作符->:

#include 

usingnamespacestd;

structTest {

intnum;

voidfunc() {}

};

// Notice the extra "Test::" in the pointer type

intTest::*ptr_num = &Test::num;

void(Test::*ptr_func)() = &Test::func;

intmain() {

Test t;

Test *pt = newTest;

// Call the stored member function

(t.*ptr_func)();

(pt->*ptr_func)();

// Set the variable in the stored member slot

t.*ptr_num = 1;

pt->*ptr_num = 2;

deletept;

return0;

}

该特征实际上十分有用,尤其在写库的时候。例如,Boost::Python, 一个用来将C++绑定到Python对象的库,就使用成员指针操作符,在包装对象时很容易的指向成员。

#include 

#include 

usingnamespaceboost::python;

structWorld {

std::string msg;

voidgreet() { std::cout <

};

BOOST_PYTHON_MODULE(hello) {

class_("World")

.def_readwrite("msg", &World::msg)

.def("greet", &World::greet);

}

记住使用成员函数指针与普通函数指针是不同的。在成员函数指针和普通函数指针之间casting是无效的。例如,Microsoft编译器里的成员 函数使用了一个称为thiscall的优化调用约定,thiscall将this参数放到ecx寄存器里,而普通函数的调用约定却是在栈上解析所有的参 数。

而且,成员函数指针可能比普通指针大四倍左右,编译器需要存储函数体的地址,到正确父地址(多个继承)的偏移,虚函数表(虚继承)中另一个偏移的索引,甚至在对象自身内部的虚函数表的偏移也需要存储(为了前向声明类型)。

#include 

structA {};

structB :virtualA {};

structC {};

structD : A, C {};

structE;

intmain() {

std::cout <

std::cout <

std::cout <

std::cout <

return0;

}

// 32-bit Visual C++ 2008:  A = 4, B = 8, D = 12, E = 16

// 32-bit GCC 4.2.1:        A = 8, B = 8, D = 8,  E = 8

// 32-bit Digital Mars C++: A = 4, B = 4, D = 4,  E = 4

在Digital Mars编译器里所有的成员函数都是相同的大小,这是源于这样一个聪明的设计:生成“thunk”函数来运用右偏移而不是存储指针自身内部的偏移。

静态实例方法

C++中可以通过实例调用静态方法也可以通过类直接调用。这可以使你不需要更新任何调用点就可以将实例方法修改为静态方法。

structFoo {

staticvoidfoo() {}

};

// These are equivalent

Foo::foo();

Foo().foo();

重载++和–

C++的设计中自定义操作符的函数名称就是操作符本身,这在大部分情况下都工作的很好。例如,一元操作符的-和二元操作符的-(取反和相减)可以通 过参数个数来区分。但这对于一元递增和递减操作符却不奏效,因为它们的特征似乎完全相同。C++语言有一个很笨拙的技巧来解决这个问题:后缀++和–操作 符必须有一个空的int参数作为标记让编译器知道要进行后缀操作(是的,只有int类型有效)。

structNumber {

Number &operator ++ (); // Generate a prefix ++ operator

Number operator ++ (int);// Generate a postfix ++ operator

};

操作符重载和检查顺序

重载,(逗号),||或者&&操作符会引起混乱,因为它打破了正常的检查规则。通常情况下,逗号操作符在整个左边检查完毕才开始检 查右边,|| 和 &&操作符有短路行为:仅在必要时才会去检查右边。无论如何,操作符的重载版本仅仅是函数调用且函数调用以未指定的顺序检查它们的参数。

重载这些操作符只是一种滥用C++语法的方式。作为一个实例,下面我给出一个Python形式的无括号版打印语句的C++实现:

#include 

namespace__hidden__ {

structprint {

boolspace;

print() : space(false) {}

~print() { std::cout <

template

print &operator , (constT &t) {

if(space) std::cout <

elsespace =true;

std::cout <

return*this;

}

};

}

#define print __hidden__::print(),

intmain() {

inta = 1, b = 2;

print "this is a test";

print "the sum of", a,"and", b,"is", a + b;

return0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值