通常,'using'声明用于将基本类的一些成员函数纳入范围,否则这些函数将被隐藏.从这个角度来看,它只是一种使可访问信息更便于使用的机制.
但是:'using'声明也可用于更改访问约束(不仅用于函数,还用于属性).例如:
class C{
public:
int a;
void g(){ cout << "C:g()\n"; }
C() : a(0){}
};
class D : public C{
private:
using C::a;
using C::g;
public:
D() { a = 1; }
};
int main(void){
D d;
cout << d.a << endl; //error: a is inaccessible
C *cp = &d;
cout << cp->a << endl; //works
d.g(); //error: g is inaccessible
cp->g(); //works
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我认为派生类中的访问限制实际上没有用,因为你总是可以从指向基类的指针访问g()和a.那么至少应该有某种编译器警告吗?或者禁止衍生类的访问限制更好?使用声明不是添加约束以进行访问的唯一可能性.它也可以通过覆盖基类的函数并将其放在具有更多访问限制的部分中来完成.是否有一些合理的例子,以这种方式限制访问确实是不可取的?如果不是,我不明白为什么应该允许它.
还有一件事:至少使用g ++,相同的代码编译得很好而没有"使用"这个词.这意味着对于上面的例子:可以编写C :: a; 和C :: g; 而不是使用C :: a; 使用C …
我仔细研究了C++ 11标准(以及n3242草案)和互联网,但未找到准确的答案.下面的代码使用clang 3.2和g ++ 4.7.2以及Visual Studio 2010进行编译,但我希望会收到错误.
#include <iostream>
#include <typeinfo>
typedef int a_t;
namespace a_ns
{
class a_t {};
}
using a_ns::a_t;
int main()
{
a_t a;
std::cout << typeid(a).name() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
内置:
clang -std=c++11 -pedantic -Wall -o a a.cpp -lstdc++
g++ -std=c++11 -pedantic -Wall -o a a.cpp -lstdc++
cl -EHsc -GR a.cpp
Run Code Online (Sandbox Code Playgroud)
clang和g ++生成的可执行文件打印"i",这似乎表明a是int类型而typedef占了上风.cl生成的可执行文件打印"class a_ns :: a_t",这似乎表明Visual Studio更喜欢使用声明.
我希望代码不要按照以下标准摘录编译.我希望类似于"使用声明的目标与已经在范围内的声明冲突"的错误.
7.1.3.6类似地,在给定的范围内,类或枚举不应声明与在该范围内声明的typedef-name具有相同的名称,并且引用除类或枚举本身以外的类型.
7.3.3.1 using声明在声明区域中引入了一个名称,其中出现using声明.
7.3.3.2每份使用声明均为声明[...]
标准中可能缺少一些可以解释这种行为的东西(或者我太累了,看不到明显的),但我似乎无法找到它.
谢谢.
我有一个类('TestC'),它派生自另外两个类('TestA'和'TestB'),两个类都有一个具有相同签名的虚函数.
要通过'TestC'访问该功能,我必须告诉它使用哪个版本.如果我明确覆盖'TestC'中的函数并调用我想要的版本,这是有效的:
#include <iostream>
class TestA
{
public:
virtual void test() {std::cout<<"a";}
};
class TestB
{
public:
virtual void test() {std::cout<<"b";}
};
class TestC
: public TestA,public TestB
{
public:
void test() {TestB::test();}
};
int main(int argc,char *argv[])
{
TestC c;
TestA *a = static_cast<TestA*>(&c);
a->test();
c.test();
for(;;);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
输出:"bb"
这是预期的结果.但是,我注意到如果我使用'using'关键字,而不是显式覆盖函数,我会得到一些意想不到的行为:
class TestC
: public TestA,public TestB
{
public:
using TestB::test;
};
Run Code Online (Sandbox Code Playgroud)
(其他一切都是一样的)
输出:"ab"
谁可以给我解释一下这个?看起来'测试'突然变得不再虚拟了?有没有办法做到这一点,没有明确覆盖功能?(像"使用覆盖"之类的东西)
当使用using继承基类的构造函数时,英特尔C++编译器(版本16.0.3.207 Build 20160415)似乎删除了显式说明符.这是一个错误吗?
struct B
{
explicit B(int) { }
};
struct D : B
{
using B::B;
};
B b = 1; // Not OK, fine
D d = 1; // Not OK with Microsoft C++ and GCC, but OK with Intel C++
Run Code Online (Sandbox Code Playgroud) 我尝试创建无法与原始别名区分开的模板别名。
因此,我创建特征以检查2个模板(非类型)是否相等:
template <template <class...> class C1,
template <class...> class C2>
struct is_same_template : std::false_type {};
template <template <class...> class C1>
struct is_same_template<C1, C1> : std::true_type {};
Run Code Online (Sandbox Code Playgroud)
现在测试一下:
// Expected alias
template <typename ... Ts> using V_Ts = std::vector<Ts...>; // Variadic
// Fallback alias
template <typename T, typename A> using V = std::vector<T, A>; // Exact count
static_assert(!is_same_template<std::vector, V_Ts>::value); // Alias rejected by gcc/clang
static_assert( is_same_template<std::vector, V>::value); // Alias accepted only for gcc
Run Code Online (Sandbox Code Playgroud)
是否可以创建“ true”别名?哪个编译器是正确的?
是否可以使用typedef或using在概念中声明类型别名,如概念TS所提议的那样?如果我尝试类似下面的MWE,代码不会编译(使用gcc 6.2.1和-fconcepts开关)
#include <type_traits>
template<typename T>
concept bool TestConcept ()
{
return requires(T t)
{
using V = T;
std::is_integral<V>::value;
};
}
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果错误:
main.cpp: In function ‘concept bool TestConcept()’:
main.cpp:8:9: error: expected primary-expression before ‘using’
using V = T;
^~~~~
main.cpp:8:9: error: expected ‘}’ before ‘using’
main.cpp:8:9: error: expected ‘;’ before ‘using’
main.cpp:4:14: error: definition of concept ‘concept bool TestConcept()’ has multiple statements
concept bool TestConcept ()
^~~~~~~~~~~ …Run Code Online (Sandbox Code Playgroud) 在从class B继承的类中A,可以使用using声明将in的成员(甚至是模板)带A进去B,如下所示:
struct A {
template <typename T>
void foo();
};
struct B : private A {
using A::foo;
};
Run Code Online (Sandbox Code Playgroud)
但是可以为转换模板完成吗?
struct A {
template <typename T>
operator T();
};
struct B : private A {
using A::operator /* ??? */;
};
Run Code Online (Sandbox Code Playgroud)
似乎没有办法通过名称来引用模板,但是我希望被证明是错误的或得到一些澄清。
c++ inheritance using-declaration conversion-operator language-lawyer
使用声明似乎不适用于枚举类型
class Sample{
public:
enum Colour { RED,BLUE,GREEN};
}
using Sample::Colour;
Run Code Online (Sandbox Code Playgroud)
不起作用!! 我们是否需要为枚举类型的每个枚举器添加使用声明?如下
using sample::Colour::RED;
Run Code Online (Sandbox Code Playgroud) 从C++ 11标准,§7.3.3[namespace.udecl]/1:
using声明在声明区域中引入了一个名称,其中出现using声明.
使用声明:
using typenameopt nested-name-specifier unqualified-id;
using ::unqualified-id;using声明中指定的成员名称在using声明出现的声明区域中声明.
在使用声明发生的声明性区域中声明的名称是什么意思?
这是否意味着将该名称引入发生using声明的声明性区域?
声明名称和声明名称所代表的实体之间是否有区别?
例:
namespace N { static int i = 1; } /* Declares an entity denoted by
the name i in the declarative region of the namespace N.
Introduces the name into the declarative region of the namespace N.
Declares the name i in the declarative region of the namespace N? */
using N::i; /* Declares the name i in the declarative …Run Code Online (Sandbox Code Playgroud) using基础构造函数的声明是私有的,但仍然可以构造该类.为什么?
可访问性对于必须公开operator[]的using声明的工作方式不同.
#include <vector>
template<typename T>
class Vec : std::vector<T>
{
private:
using std::vector<T>::vector; // Works, even if private. Why?
public:
using std::vector<T>::operator[]; // must be public
};
int main(){
Vec<int> vec = {2, 2};
auto test = vec[1];
}
Run Code Online (Sandbox Code Playgroud)
如果我希望构造函数是私有的,该怎么办?可以用using声明来完成吗?
c++ ×10
c++11 ×2
inheritance ×2
typedef ×2
c++-concepts ×1
constructor ×1
declaration ×1
entity ×1
enums ×1
icc ×1
overriding ×1
scope ×1